1 | /* |
2 | * Copyright (c) Facebook, Inc. and its affiliates. |
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/Portability.h> |
26 | #include <folly/Traits.h> |
27 | |
28 | namespace folly { |
29 | |
30 | /** |
31 | * copy |
32 | * |
33 | * Usable when you have a function with two overloads: |
34 | * |
35 | * class MyData; |
36 | * void something(MyData&&); |
37 | * void something(const MyData&); |
38 | * |
39 | * Where the purpose is to make copies and moves explicit without having to |
40 | * spell out the full type names - in this case, for copies, to invoke copy |
41 | * constructors. |
42 | * |
43 | * When the caller wants to pass a copy of an lvalue, the caller may: |
44 | * |
45 | * void foo() { |
46 | * MyData data; |
47 | * something(folly::copy(data)); // explicit copy |
48 | * something(std::move(data)); // explicit move |
49 | * something(data); // const& - neither move nor copy |
50 | * } |
51 | * |
52 | * Note: If passed an rvalue, invokes the move-ctor, not the copy-ctor. This |
53 | * can be used to to force a move, where just using std::move would not: |
54 | * |
55 | * folly::copy(std::move(data)); // force-move, not just a cast to && |
56 | * |
57 | * Note: The following text appears in the standard: |
58 | * |
59 | * > In several places in this Clause the operation //DECAY_COPY(x)// is used. |
60 | * > All such uses mean call the function `decay_copy(x)` and use the result, |
61 | * > where `decay_copy` is defined as follows: |
62 | * > |
63 | * > template <class T> decay_t<T> decay_copy(T&& v) |
64 | * > { return std::forward<T>(v); } |
65 | * > |
66 | * > http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4296.pdf |
67 | * > 30.2.6 `decay_copy` [thread.decaycopy]. |
68 | * |
69 | * We mimic it, with a `noexcept` specifier for good measure. |
70 | */ |
71 | |
72 | template <typename T> |
73 | constexpr typename std::decay<T>::type copy(T&& value) noexcept( |
74 | noexcept(typename std::decay<T>::type(std::forward<T>(value)))) { |
75 | return std::forward<T>(value); |
76 | } |
77 | |
78 | /** |
79 | * A simple helper for getting a constant reference to an object. |
80 | * |
81 | * Example: |
82 | * |
83 | * std::vector<int> v{1,2,3}; |
84 | * // The following two lines are equivalent: |
85 | * auto a = const_cast<const std::vector<int>&>(v).begin(); |
86 | * auto b = folly::as_const(v).begin(); |
87 | * |
88 | * Like C++17's std::as_const. See http://wg21.link/p0007 |
89 | */ |
90 | #if __cpp_lib_as_const || _LIBCPP_STD_VER > 14 || _MSC_VER |
91 | |
92 | /* using override */ using std::as_const; |
93 | |
94 | #else |
95 | |
96 | template <class T> |
97 | constexpr T const& as_const(T& t) noexcept { |
98 | return t; |
99 | } |
100 | |
101 | template <class T> |
102 | void as_const(T const&&) = delete; |
103 | |
104 | #endif |
105 | |
106 | // mimic: forward_like, p0847r0 |
107 | template <typename Src, typename Dst> |
108 | constexpr like_t<Src, Dst>&& forward_like(Dst&& dst) noexcept { |
109 | return static_cast<like_t<Src, Dst>&&>(std::forward<Dst>(dst)); |
110 | } |
111 | |
112 | /** |
113 | * Backports from C++17 of: |
114 | * std::in_place_t |
115 | * std::in_place_type_t |
116 | * std::in_place_index_t |
117 | * std::in_place |
118 | * std::in_place_type |
119 | * std::in_place_index |
120 | */ |
121 | |
122 | struct in_place_tag {}; |
123 | template <class> |
124 | struct in_place_type_tag {}; |
125 | template <std::size_t> |
126 | struct in_place_index_tag {}; |
127 | |
128 | using in_place_t = in_place_tag (&)(in_place_tag); |
129 | template <class T> |
130 | using in_place_type_t = in_place_type_tag<T> (&)(in_place_type_tag<T>); |
131 | template <std::size_t I> |
132 | using in_place_index_t = in_place_index_tag<I> (&)(in_place_index_tag<I>); |
133 | |
134 | inline in_place_tag in_place(in_place_tag = {}) { |
135 | return {}; |
136 | } |
137 | template <class T> |
138 | inline in_place_type_tag<T> in_place_type(in_place_type_tag<T> = {}) { |
139 | return {}; |
140 | } |
141 | template <std::size_t I> |
142 | inline in_place_index_tag<I> in_place_index(in_place_index_tag<I> = {}) { |
143 | return {}; |
144 | } |
145 | |
146 | /** |
147 | * Initializer lists are a powerful compile time syntax introduced in C++11 |
148 | * but due to their often conflicting syntax they are not used by APIs for |
149 | * construction. |
150 | * |
151 | * Further standard conforming compilers *strongly* favor an |
152 | * std::initializer_list overload for construction if one exists. The |
153 | * following is a simple tag used to disambiguate construction with |
154 | * initializer lists and regular uniform initialization. |
155 | * |
156 | * For example consider the following case |
157 | * |
158 | * class Something { |
159 | * public: |
160 | * explicit Something(int); |
161 | * Something(std::intiializer_list<int>); |
162 | * |
163 | * operator int(); |
164 | * }; |
165 | * |
166 | * ... |
167 | * Something something{1}; // SURPRISE!! |
168 | * |
169 | * The last call to instantiate the Something object will go to the |
170 | * initializer_list overload. Which may be surprising to users. |
171 | * |
172 | * If however this tag was used to disambiguate such construction it would be |
173 | * easy for users to see which construction overload their code was referring |
174 | * to. For example |
175 | * |
176 | * class Something { |
177 | * public: |
178 | * explicit Something(int); |
179 | * Something(folly::initlist_construct_t, std::initializer_list<int>); |
180 | * |
181 | * operator int(); |
182 | * }; |
183 | * |
184 | * ... |
185 | * Something something_one{1}; // not the initializer_list overload |
186 | * Something something_two{folly::initlist_construct, {1}}; // correct |
187 | */ |
188 | struct initlist_construct_t {}; |
189 | constexpr initlist_construct_t initlist_construct{}; |
190 | |
191 | // sorted_unique_t, sorted_unique |
192 | // |
193 | // A generic tag type and value to indicate that some constructor or method |
194 | // accepts a container in which the values are sorted and unique. |
195 | // |
196 | // Example: |
197 | // |
198 | // void takes_numbers(folly::sorted_unique_t, std::vector<int> alist) { |
199 | // assert(std::is_sorted(alist.begin(), alist.end())); |
200 | // assert(std::unique(alist.begin(), alist.end()) == alist.end()); |
201 | // for (i : alist) { |
202 | // // some behavior which safe only when alist is sorted and unique |
203 | // } |
204 | // } |
205 | // void takes_numbers(std::vector<int> alist) { |
206 | // std::sort(alist.begin(), alist.end()); |
207 | // alist.erase(std::unique(alist.begin(), alist.end()), alist.end()); |
208 | // takes_numbers(folly::sorted_unique, alist); |
209 | // } |
210 | // |
211 | // mimic: std::sorted_unique_t, std::sorted_unique, p0429r6 |
212 | struct sorted_unique_t {}; |
213 | constexpr sorted_unique_t sorted_unique; |
214 | |
215 | // sorted_equivalent_t, sorted_equivalent |
216 | // |
217 | // A generic tag type and value to indicate that some constructor or method |
218 | // accepts a container in which the values are sorted but not necessarily |
219 | // unique. |
220 | // |
221 | // Example: |
222 | // |
223 | // void takes_numbers(folly::sorted_equivalent_t, std::vector<int> alist) { |
224 | // assert(std::is_sorted(alist.begin(), alist.end())); |
225 | // for (i : alist) { |
226 | // // some behavior which safe only when alist is sorted |
227 | // } |
228 | // } |
229 | // void takes_numbers(std::vector<int> alist) { |
230 | // std::sort(alist.begin(), alist.end()); |
231 | // takes_numbers(folly::sorted_equivalent, alist); |
232 | // } |
233 | // |
234 | // mimic: std::sorted_equivalent_t, std::sorted_equivalent, p0429r6 |
235 | struct sorted_equivalent_t {}; |
236 | constexpr sorted_equivalent_t sorted_equivalent; |
237 | |
238 | template <typename T> |
239 | struct transparent : T { |
240 | using is_transparent = void; |
241 | using T::T; |
242 | }; |
243 | |
244 | /** |
245 | * A simple function object that passes its argument through unchanged. |
246 | * |
247 | * Example: |
248 | * |
249 | * int i = 42; |
250 | * int &j = Identity()(i); |
251 | * assert(&i == &j); |
252 | * |
253 | * Warning: passing a prvalue through Identity turns it into an xvalue, |
254 | * which can effect whether lifetime extension occurs or not. For instance: |
255 | * |
256 | * auto&& x = std::make_unique<int>(42); |
257 | * cout << *x ; // OK, x refers to a valid unique_ptr. |
258 | * |
259 | * auto&& y = Identity()(std::make_unique<int>(42)); |
260 | * cout << *y ; // ERROR: y did not lifetime-extend the unique_ptr. It |
261 | * // is no longer valid |
262 | */ |
263 | struct Identity { |
264 | template <class T> |
265 | constexpr T&& operator()(T&& x) const noexcept { |
266 | return static_cast<T&&>(x); |
267 | } |
268 | }; |
269 | |
270 | namespace moveonly_ { // Protection from unintended ADL. |
271 | |
272 | /** |
273 | * Disallow copy but not move in derived types. This is essentially |
274 | * boost::noncopyable (the implementation is almost identical) but it |
275 | * doesn't delete move constructor and move assignment. |
276 | */ |
277 | class MoveOnly { |
278 | protected: |
279 | constexpr MoveOnly() = default; |
280 | ~MoveOnly() = default; |
281 | |
282 | MoveOnly(MoveOnly&&) = default; |
283 | MoveOnly& operator=(MoveOnly&&) = default; |
284 | MoveOnly(const MoveOnly&) = delete; |
285 | MoveOnly& operator=(const MoveOnly&) = delete; |
286 | }; |
287 | |
288 | } // namespace moveonly_ |
289 | |
290 | using MoveOnly = moveonly_::MoveOnly; |
291 | |
292 | template <typename T> |
293 | constexpr auto to_signed(T const& t) -> typename std::make_signed<T>::type { |
294 | using S = typename std::make_signed<T>::type; |
295 | // note: static_cast<S>(t) would be more straightforward, but it would also be |
296 | // implementation-defined behavior and that is typically to be avoided; the |
297 | // following code optimized into the same thing, though |
298 | constexpr auto m = static_cast<T>(std::numeric_limits<S>::max()); |
299 | return m < t ? -static_cast<S>(~t) + S{-1} : static_cast<S>(t); |
300 | } |
301 | |
302 | template <typename T> |
303 | constexpr auto to_unsigned(T const& t) -> typename std::make_unsigned<T>::type { |
304 | using U = typename std::make_unsigned<T>::type; |
305 | return static_cast<U>(t); |
306 | } |
307 | |
308 | template <typename Src> |
309 | class to_narrow_convertible { |
310 | public: |
311 | static_assert(std::is_integral<Src>::value, "not an integer" ); |
312 | |
313 | explicit constexpr to_narrow_convertible(Src const& value) noexcept |
314 | : value_(value) {} |
315 | #if __cplusplus >= 201703L |
316 | explicit to_narrow_convertible(to_narrow_convertible const&) = default; |
317 | explicit to_narrow_convertible(to_narrow_convertible&&) = default; |
318 | #else |
319 | to_narrow_convertible(to_narrow_convertible const&) = default; |
320 | to_narrow_convertible(to_narrow_convertible&&) = default; |
321 | #endif |
322 | to_narrow_convertible& operator=(to_narrow_convertible const&) = default; |
323 | to_narrow_convertible& operator=(to_narrow_convertible&&) = default; |
324 | |
325 | template < |
326 | typename Dst, |
327 | std::enable_if_t< |
328 | std::is_integral<Dst>::value && |
329 | std::is_signed<Dst>::value == std::is_signed<Src>::value, |
330 | int> = 0> |
331 | /* implicit */ constexpr operator Dst() const noexcept { |
332 | FOLLY_PUSH_WARNING |
333 | FOLLY_GNU_DISABLE_WARNING("-Wconversion" ) |
334 | return value_; |
335 | FOLLY_POP_WARNING |
336 | } |
337 | |
338 | private: |
339 | Src value_; |
340 | }; |
341 | |
342 | // to_narrow |
343 | // |
344 | // A utility for performing explicit possibly-narrowing integral conversion |
345 | // without specifying the destination type. Does not permit changing signs. |
346 | // Sometimes preferable to static_cast<Dst>(src) to document the intended |
347 | // semantics of the cast. |
348 | // |
349 | // Models explicit conversion with an elided destination type. Sits in between |
350 | // a stricter explicit conversion with a named destination type and a more |
351 | // lenient implicit conversion. Implemented with implicit conversion in order |
352 | // to take advantage of the undefined-behavior sanitizer's inspection of all |
353 | // implicit conversions - it checks for truncation, with suppressions in place |
354 | // for warnings which guard against narrowing implicit conversions. |
355 | template <typename Src> |
356 | constexpr auto to_narrow(Src const& src) -> to_narrow_convertible<Src> { |
357 | return to_narrow_convertible<Src>{src}; |
358 | } |
359 | |
360 | template <class E> |
361 | constexpr std::underlying_type_t<E> to_underlying(E e) noexcept { |
362 | static_assert(std::is_enum<E>::value, "not an enum type" ); |
363 | return static_cast<std::underlying_type_t<E>>(e); |
364 | } |
365 | |
366 | } // namespace folly |
367 | |