1 | /* |
2 | * Copyright 2016-present Facebook, Inc. |
3 | * |
4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
5 | * you may not use this file except in compliance with the License. |
6 | * You may obtain a copy of the License at |
7 | * |
8 | * http://www.apache.org/licenses/LICENSE-2.0 |
9 | * |
10 | * Unless required by applicable law or agreed to in writing, software |
11 | * distributed under the License is distributed on an "AS IS" BASIS, |
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
13 | * See the License for the specific language governing permissions and |
14 | * limitations under the License. |
15 | */ |
16 | |
17 | #pragma once |
18 | |
19 | #include <cstdint> |
20 | #include <limits> |
21 | #include <type_traits> |
22 | #include <utility> |
23 | |
24 | #include <folly/CPortability.h> |
25 | #include <folly/Traits.h> |
26 | |
27 | namespace folly { |
28 | |
29 | /** |
30 | * copy |
31 | * |
32 | * Usable when you have a function with two overloads: |
33 | * |
34 | * class MyData; |
35 | * void something(MyData&&); |
36 | * void something(const MyData&); |
37 | * |
38 | * Where the purpose is to make copies and moves explicit without having to |
39 | * spell out the full type names - in this case, for copies, to invoke copy |
40 | * constructors. |
41 | * |
42 | * When the caller wants to pass a copy of an lvalue, the caller may: |
43 | * |
44 | * void foo() { |
45 | * MyData data; |
46 | * something(folly::copy(data)); // explicit copy |
47 | * something(std::move(data)); // explicit move |
48 | * something(data); // const& - neither move nor copy |
49 | * } |
50 | * |
51 | * Note: If passed an rvalue, invokes the move-ctor, not the copy-ctor. This |
52 | * can be used to to force a move, where just using std::move would not: |
53 | * |
54 | * std::copy(std::move(data)); // force-move, not just a cast to && |
55 | * |
56 | * Note: The following text appears in the standard: |
57 | * |
58 | * > In several places in this Clause the operation //DECAY_COPY(x)// is used. |
59 | * > All such uses mean call the function `decay_copy(x)` and use the result, |
60 | * > where `decay_copy` is defined as follows: |
61 | * > |
62 | * > template <class T> decay_t<T> decay_copy(T&& v) |
63 | * > { return std::forward<T>(v); } |
64 | * > |
65 | * > http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4296.pdf |
66 | * > 30.2.6 `decay_copy` [thread.decaycopy]. |
67 | * |
68 | * We mimic it, with a `noexcept` specifier for good measure. |
69 | */ |
70 | |
71 | template <typename T> |
72 | constexpr typename std::decay<T>::type copy(T&& value) noexcept( |
73 | noexcept(typename std::decay<T>::type(std::forward<T>(value)))) { |
74 | return std::forward<T>(value); |
75 | } |
76 | |
77 | /** |
78 | * A simple helper for getting a constant reference to an object. |
79 | * |
80 | * Example: |
81 | * |
82 | * std::vector<int> v{1,2,3}; |
83 | * // The following two lines are equivalent: |
84 | * auto a = const_cast<const std::vector<int>&>(v).begin(); |
85 | * auto b = folly::as_const(v).begin(); |
86 | * |
87 | * Like C++17's std::as_const. See http://wg21.link/p0007 |
88 | */ |
89 | #if __cpp_lib_as_const || _LIBCPP_STD_VER > 14 || _MSC_VER |
90 | |
91 | /* using override */ using std::as_const; |
92 | |
93 | #else |
94 | |
95 | template <class T> |
96 | constexpr T const& as_const(T& t) noexcept { |
97 | return t; |
98 | } |
99 | |
100 | template <class T> |
101 | void as_const(T const&&) = delete; |
102 | |
103 | #endif |
104 | |
105 | // mimic: forward_like, p0847r0 |
106 | template <typename Src, typename Dst> |
107 | constexpr like_t<Src, Dst>&& forward_like(Dst&& dst) noexcept { |
108 | return static_cast<like_t<Src, Dst>&&>(std::forward<Dst>(dst)); |
109 | } |
110 | |
111 | #if __cpp_lib_exchange_function || _LIBCPP_STD_VER > 11 || _MSC_VER |
112 | |
113 | /* using override */ using std::exchange; |
114 | |
115 | #else |
116 | |
117 | // mimic: std::exchange, C++14 |
118 | // from: http://en.cppreference.com/w/cpp/utility/exchange, CC-BY-SA |
119 | template <class T, class U = T> |
120 | T exchange(T& obj, U&& new_value) { |
121 | T old_value = std::move(obj); |
122 | obj = std::forward<U>(new_value); |
123 | return old_value; |
124 | } |
125 | |
126 | #endif |
127 | |
128 | namespace utility_detail { |
129 | template <typename...> |
130 | struct make_seq_cat; |
131 | template < |
132 | template <typename T, T...> class S, |
133 | typename T, |
134 | T... Ta, |
135 | T... Tb, |
136 | T... Tc> |
137 | struct make_seq_cat<S<T, Ta...>, S<T, Tb...>, S<T, Tc...>> { |
138 | using type = |
139 | S<T, |
140 | Ta..., |
141 | (sizeof...(Ta) + Tb)..., |
142 | (sizeof...(Ta) + sizeof...(Tb) + Tc)...>; |
143 | }; |
144 | |
145 | // Not parameterizing by `template <typename T, T...> class, typename` because |
146 | // clang precisely v4.0 fails to compile that. Note that clang v3.9 and v5.0 |
147 | // handle that code correctly. |
148 | // |
149 | // For this to work, `S0` is required to be `Sequence<T>` and `S1` is required |
150 | // to be `Sequence<T, 0>`. |
151 | |
152 | template <std::size_t Size> |
153 | struct make_seq { |
154 | template <typename S0, typename S1> |
155 | using apply = typename make_seq_cat< |
156 | typename make_seq<Size / 2>::template apply<S0, S1>, |
157 | typename make_seq<Size / 2>::template apply<S0, S1>, |
158 | typename make_seq<Size % 2>::template apply<S0, S1>>::type; |
159 | }; |
160 | template <> |
161 | struct make_seq<1> { |
162 | template <typename S0, typename S1> |
163 | using apply = S1; |
164 | }; |
165 | template <> |
166 | struct make_seq<0> { |
167 | template <typename S0, typename S1> |
168 | using apply = S0; |
169 | }; |
170 | } // namespace utility_detail |
171 | |
172 | #if __cpp_lib_integer_sequence || _MSC_VER |
173 | |
174 | /* using override */ using std::index_sequence; |
175 | /* using override */ using std::integer_sequence; |
176 | |
177 | #else |
178 | |
179 | // TODO: Remove after upgrading to C++14 baseline |
180 | |
181 | template <class T, T... Ints> |
182 | struct integer_sequence { |
183 | using value_type = T; |
184 | |
185 | static constexpr std::size_t size() noexcept { |
186 | return sizeof...(Ints); |
187 | } |
188 | }; |
189 | |
190 | template <std::size_t... Ints> |
191 | using index_sequence = integer_sequence<std::size_t, Ints...>; |
192 | |
193 | #endif |
194 | |
195 | #if FOLLY_HAS_BUILTIN(__make_integer_seq) || _MSC_FULL_VER >= 190023918 |
196 | |
197 | template <typename T, std::size_t Size> |
198 | using make_integer_sequence = __make_integer_seq<integer_sequence, T, Size>; |
199 | |
200 | #else |
201 | |
202 | template <typename T, std::size_t Size> |
203 | using make_integer_sequence = typename utility_detail::make_seq< |
204 | Size>::template apply<integer_sequence<T>, integer_sequence<T, 0>>; |
205 | |
206 | #endif |
207 | |
208 | template <std::size_t Size> |
209 | using make_index_sequence = make_integer_sequence<std::size_t, Size>; |
210 | template <class... T> |
211 | using index_sequence_for = make_index_sequence<sizeof...(T)>; |
212 | |
213 | /** |
214 | * Backports from C++17 of: |
215 | * std::in_place_t |
216 | * std::in_place_type_t |
217 | * std::in_place_index_t |
218 | * std::in_place |
219 | * std::in_place_type |
220 | * std::in_place_index |
221 | */ |
222 | |
223 | struct in_place_tag {}; |
224 | template <class> |
225 | struct in_place_type_tag {}; |
226 | template <std::size_t> |
227 | struct in_place_index_tag {}; |
228 | |
229 | using in_place_t = in_place_tag (&)(in_place_tag); |
230 | template <class T> |
231 | using in_place_type_t = in_place_type_tag<T> (&)(in_place_type_tag<T>); |
232 | template <std::size_t I> |
233 | using in_place_index_t = in_place_index_tag<I> (&)(in_place_index_tag<I>); |
234 | |
235 | inline in_place_tag in_place(in_place_tag = {}) { |
236 | return {}; |
237 | } |
238 | template <class T> |
239 | inline in_place_type_tag<T> in_place_type(in_place_type_tag<T> = {}) { |
240 | return {}; |
241 | } |
242 | template <std::size_t I> |
243 | inline in_place_index_tag<I> in_place_index(in_place_index_tag<I> = {}) { |
244 | return {}; |
245 | } |
246 | |
247 | /** |
248 | * Initializer lists are a powerful compile time syntax introduced in C++11 |
249 | * but due to their often conflicting syntax they are not used by APIs for |
250 | * construction. |
251 | * |
252 | * Further standard conforming compilers *strongly* favor an |
253 | * std::initializer_list overload for construction if one exists. The |
254 | * following is a simple tag used to disambiguate construction with |
255 | * initializer lists and regular uniform initialization. |
256 | * |
257 | * For example consider the following case |
258 | * |
259 | * class Something { |
260 | * public: |
261 | * explicit Something(int); |
262 | * Something(std::intiializer_list<int>); |
263 | * |
264 | * operator int(); |
265 | * }; |
266 | * |
267 | * ... |
268 | * Something something{1}; // SURPRISE!! |
269 | * |
270 | * The last call to instantiate the Something object will go to the |
271 | * initializer_list overload. Which may be surprising to users. |
272 | * |
273 | * If however this tag was used to disambiguate such construction it would be |
274 | * easy for users to see which construction overload their code was referring |
275 | * to. For example |
276 | * |
277 | * class Something { |
278 | * public: |
279 | * explicit Something(int); |
280 | * Something(folly::initlist_construct_t, std::initializer_list<int>); |
281 | * |
282 | * operator int(); |
283 | * }; |
284 | * |
285 | * ... |
286 | * Something something_one{1}; // not the initializer_list overload |
287 | * Something something_two{folly::initlist_construct, {1}}; // correct |
288 | */ |
289 | struct initlist_construct_t {}; |
290 | constexpr initlist_construct_t initlist_construct{}; |
291 | |
292 | /** |
293 | * A generic tag type to indicate that some constructor or method accepts a |
294 | * presorted container. |
295 | * |
296 | * Example: |
297 | * |
298 | * void takes_numbers(std::vector<int> alist) { |
299 | * std::sort(alist.begin(), alist.end()); |
300 | * takes_numbers(folly::presorted, alist); |
301 | * } |
302 | * |
303 | * void takes_numbers(folly::presorted_t, std::vector<int> alist) { |
304 | * assert(std::is_sorted(alist.begin(), alist.end())); // debug mode only |
305 | * for (i : alist) { |
306 | * // some behavior which is defined and safe only when alist is sorted ... |
307 | * } |
308 | * } |
309 | */ |
310 | struct presorted_t {}; |
311 | constexpr presorted_t presorted{}; |
312 | |
313 | /** |
314 | * A generic tag type to indicate that some constructor or method accepts an |
315 | * unsorted container. Useful in contexts which might have some reason to assume |
316 | * a container to be sorted. |
317 | * |
318 | * Example: |
319 | * |
320 | * void takes_numbers(std::vector<int> alist) { |
321 | * takes_numbers(folly::unsorted, alist); |
322 | * } |
323 | * |
324 | * void takes_numbers(folly::unsorted_t, std::vector<int> alist) { |
325 | * std::sort(alist.begin(), alist.end()); |
326 | * for (i : alist) { |
327 | * // some behavior which is defined and safe only when alist is sorted ... |
328 | * } |
329 | * } |
330 | */ |
331 | struct unsorted_t {}; |
332 | constexpr unsorted_t unsorted{}; |
333 | |
334 | template <typename T> |
335 | struct transparent : T { |
336 | using is_transparent = void; |
337 | using T::T; |
338 | }; |
339 | |
340 | /** |
341 | * A simple function object that passes its argument through unchanged. |
342 | * |
343 | * Example: |
344 | * |
345 | * int i = 42; |
346 | * int &j = Identity()(i); |
347 | * assert(&i == &j); |
348 | * |
349 | * Warning: passing a prvalue through Identity turns it into an xvalue, |
350 | * which can effect whether lifetime extension occurs or not. For instance: |
351 | * |
352 | * auto&& x = std::make_unique<int>(42); |
353 | * cout << *x ; // OK, x refers to a valid unique_ptr. |
354 | * |
355 | * auto&& y = Identity()(std::make_unique<int>(42)); |
356 | * cout << *y ; // ERROR: y did not lifetime-extend the unique_ptr. It |
357 | * // is no longer valid |
358 | */ |
359 | struct Identity { |
360 | template <class T> |
361 | constexpr T&& operator()(T&& x) const noexcept { |
362 | return static_cast<T&&>(x); |
363 | } |
364 | }; |
365 | |
366 | namespace moveonly_ { // Protection from unintended ADL. |
367 | |
368 | /** |
369 | * Disallow copy but not move in derived types. This is essentially |
370 | * boost::noncopyable (the implementation is almost identical) but it |
371 | * doesn't delete move constructor and move assignment. |
372 | */ |
373 | class MoveOnly { |
374 | protected: |
375 | constexpr MoveOnly() = default; |
376 | ~MoveOnly() = default; |
377 | |
378 | MoveOnly(MoveOnly&&) = default; |
379 | MoveOnly& operator=(MoveOnly&&) = default; |
380 | MoveOnly(const MoveOnly&) = delete; |
381 | MoveOnly& operator=(const MoveOnly&) = delete; |
382 | }; |
383 | |
384 | } // namespace moveonly_ |
385 | |
386 | using MoveOnly = moveonly_::MoveOnly; |
387 | |
388 | template <typename T> |
389 | constexpr auto to_signed(T const& t) -> typename std::make_signed<T>::type { |
390 | using S = typename std::make_signed<T>::type; |
391 | // note: static_cast<S>(t) would be more straightforward, but it would also be |
392 | // implementation-defined behavior and that is typically to be avoided; the |
393 | // following code optimized into the same thing, though |
394 | return std::numeric_limits<S>::max() < t ? -static_cast<S>(~t) + S{-1} |
395 | : static_cast<S>(t); |
396 | } |
397 | |
398 | template <typename T> |
399 | constexpr auto to_unsigned(T const& t) -> typename std::make_unsigned<T>::type { |
400 | using U = typename std::make_unsigned<T>::type; |
401 | return static_cast<U>(t); |
402 | } |
403 | |
404 | } // namespace folly |
405 | |