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
28namespace 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
72template <typename T>
73constexpr 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
96template <class T>
97constexpr T const& as_const(T& t) noexcept {
98 return t;
99}
100
101template <class T>
102void as_const(T const&&) = delete;
103
104#endif
105
106// mimic: forward_like, p0847r0
107template <typename Src, typename Dst>
108constexpr 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
122struct in_place_tag {};
123template <class>
124struct in_place_type_tag {};
125template <std::size_t>
126struct in_place_index_tag {};
127
128using in_place_t = in_place_tag (&)(in_place_tag);
129template <class T>
130using in_place_type_t = in_place_type_tag<T> (&)(in_place_type_tag<T>);
131template <std::size_t I>
132using in_place_index_t = in_place_index_tag<I> (&)(in_place_index_tag<I>);
133
134inline in_place_tag in_place(in_place_tag = {}) {
135 return {};
136}
137template <class T>
138inline in_place_type_tag<T> in_place_type(in_place_type_tag<T> = {}) {
139 return {};
140}
141template <std::size_t I>
142inline 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 */
188struct initlist_construct_t {};
189constexpr 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
212struct sorted_unique_t {};
213constexpr 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
235struct sorted_equivalent_t {};
236constexpr sorted_equivalent_t sorted_equivalent;
237
238template <typename T>
239struct 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 */
263struct Identity {
264 template <class T>
265 constexpr T&& operator()(T&& x) const noexcept {
266 return static_cast<T&&>(x);
267 }
268};
269
270namespace 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 */
277class 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
290using MoveOnly = moveonly_::MoveOnly;
291
292template <typename T>
293constexpr 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
302template <typename T>
303constexpr 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
308template <typename Src>
309class 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.
355template <typename Src>
356constexpr auto to_narrow(Src const& src) -> to_narrow_convertible<Src> {
357 return to_narrow_convertible<Src>{src};
358}
359
360template <class E>
361constexpr 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