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 // @author: Andrei Alexandrescu
18 
19 #pragma once
20 
21 #include <functional>
22 #include <limits>
23 #include <memory>
24 #include <tuple>
25 #include <type_traits>
26 
27 #include <folly/Portability.h>
28 
29 namespace folly {
30 
31 template <typename...>
32 struct tag_t {};
33 
34 template <typename... T>
35 FOLLY_INLINE_VARIABLE constexpr tag_t<T...> tag{};
36 
37 #if __cpp_lib_bool_constant || _MSC_VER
38 
39 using std::bool_constant;
40 
41 #else
42 
43 //  mimic: std::bool_constant, C++17
44 template <bool B>
45 using bool_constant = std::integral_constant<bool, B>;
46 
47 #endif
48 
49 template <std::size_t I>
50 using index_constant = std::integral_constant<std::size_t, I>;
51 
52 namespace detail {
53 
54 //  is_instantiation_of_v
55 //  is_instantiation_of
56 //
57 //  A trait variable and type to check if a given type is an instantiation of a
58 //  class template.
59 //
60 //  Note that this only works with type template parameters. It does not work
61 //  with non-type template parameters, template template parameters, or alias
62 //  templates.
63 template <template <typename...> class, typename>
64 FOLLY_INLINE_VARIABLE constexpr bool is_instantiation_of_v = false;
65 template <template <typename...> class C, typename... T>
66 FOLLY_INLINE_VARIABLE constexpr bool is_instantiation_of_v<C, C<T...>> = true;
67 template <template <typename...> class C, typename... T>
68 struct is_instantiation_of : bool_constant<is_instantiation_of_v<C, T...>> {};
69 
70 template <typename, typename>
71 FOLLY_INLINE_VARIABLE constexpr bool is_similar_instantiation_v = false;
72 template <template <typename...> class C, typename... A, typename... B>
73 FOLLY_INLINE_VARIABLE constexpr bool
74     is_similar_instantiation_v<C<A...>, C<B...>> = true;
75 template <typename A, typename B>
76 struct is_similar_instantiation
77     : bool_constant<is_similar_instantiation_v<A, B>> {};
78 
79 } // namespace detail
80 
81 namespace detail {
82 
83 struct is_constexpr_default_constructible_ {
84   template <typename T>
85   static constexpr auto make(tag_t<T>) -> decltype(void(T()), 0) {
86     return (void(T()), 0);
87   }
88   // second param should just be: int = (void(T()), 0)
89   // but under clang 10, crash: https://bugs.llvm.org/show_bug.cgi?id=47620
90   // and, with assertions disabled, expectation failures showing compiler
91   // deviation from the language spec
92   // xcode renumbers clang versions so detection is tricky, but, if detection
93   // were desired, a combination of __apple_build_version__ and __clang_major__
94   // may be used to reduce frontend overhead under correct compilers: clang 12
95   // under xcode and clang 10 otherwise
96   template <typename T, int = make(tag<T>)>
97   static std::true_type sfinae(T*);
98   static std::false_type sfinae(void*);
99   template <typename T>
100   static constexpr bool apply =
101       decltype(sfinae(static_cast<T*>(nullptr)))::value;
102 };
103 
104 } // namespace detail
105 
106 //  is_constexpr_default_constructible_v
107 //  is_constexpr_default_constructible
108 //
109 //  A trait variable and type which determines whether the type parameter is
110 //  constexpr default-constructible, that is, default-constructible in a
111 //  constexpr context.
112 template <typename T>
113 FOLLY_INLINE_VARIABLE constexpr bool is_constexpr_default_constructible_v =
114     detail::is_constexpr_default_constructible_::apply<T>;
115 template <typename T>
116 struct is_constexpr_default_constructible
117     : bool_constant<is_constexpr_default_constructible_v<T>> {};
118 
119 /***
120  *  _t
121  *
122  *  Instead of:
123  *
124  *    using decayed = typename std::decay<T>::type;
125  *
126  *  With the C++14 standard trait aliases, we could use:
127  *
128  *    using decayed = std::decay_t<T>;
129  *
130  *  Without them, we could use:
131  *
132  *    using decayed = _t<std::decay<T>>;
133  *
134  *  Also useful for any other library with template types having dependent
135  *  member types named `type`, like the standard trait types.
136  */
137 template <typename T>
138 using _t = typename T::type;
139 
140 /**
141  * A type trait to remove all const volatile and reference qualifiers on a
142  * type T
143  */
144 template <typename T>
145 struct remove_cvref {
146   using type =
147       typename std::remove_cv<typename std::remove_reference<T>::type>::type;
148 };
149 template <typename T>
150 using remove_cvref_t = typename remove_cvref<T>::type;
151 
152 namespace detail {
153 template <typename Src>
154 struct like_ {
155   template <typename Dst>
156   using apply = Dst;
157 };
158 template <typename Src>
159 struct like_<Src const> {
160   template <typename Dst>
161   using apply = Dst const;
162 };
163 template <typename Src>
164 struct like_<Src volatile> {
165   template <typename Dst>
166   using apply = Dst volatile;
167 };
168 template <typename Src>
169 struct like_<Src const volatile> {
170   template <typename Dst>
171   using apply = Dst const volatile;
172 };
173 template <typename Src>
174 struct like_<Src&> {
175   template <typename Dst>
176   using apply = typename like_<Src>::template apply<Dst>&;
177 };
178 template <typename Src>
179 struct like_<Src&&> {
180   template <typename Dst>
181   using apply = typename like_<Src>::template apply<Dst>&&;
182 };
183 } // namespace detail
184 
185 //  mimic: like_t, p0847r0
186 template <typename Src, typename Dst>
187 using like_t = typename detail::like_<Src>::template apply<remove_cvref_t<Dst>>;
188 
189 //  mimic: like, p0847r0
190 template <typename Src, typename Dst>
191 struct like {
192   using type = like_t<Src, Dst>;
193 };
194 
195 /**
196  *  type_t
197  *
198  *  A type alias for the first template type argument. `type_t` is useful for
199  *  controlling class-template and function-template partial specialization.
200  *
201  *  Example:
202  *
203  *    template <typename Value>
204  *    class Container {
205  *     public:
206  *      template <typename... Args>
207  *      Container(
208  *          type_t<in_place_t, decltype(Value(std::declval<Args>()...))>,
209  *          Args&&...);
210  *    };
211  *
212  *  void_t
213  *
214  *  A type alias for `void`. `void_t` is useful for controling class-template
215  *  and function-template partial specialization.
216  *
217  *  Example:
218  *
219  *    // has_value_type<T>::value is true if T has a nested type `value_type`
220  *    template <class T, class = void>
221  *    struct has_value_type
222  *        : std::false_type {};
223  *
224  *    template <class T>
225  *    struct has_value_type<T, folly::void_t<typename T::value_type>>
226  *        : std::true_type {};
227  */
228 
229 /**
230  * There is a bug in libstdc++, libc++, and MSVC's STL that causes it to
231  * ignore unused template parameter arguments in template aliases and does not
232  * cause substitution failures. This defect has been recorded here:
233  * http://open-std.org/JTC1/SC22/WG21/docs/cwg_defects.html#1558.
234  *
235  * This causes the implementation of std::void_t to be buggy, as it is likely
236  * defined as something like the following:
237  *
238  *  template <typename...>
239  *  using void_t = void;
240  *
241  * This causes the compiler to ignore all the template arguments and does not
242  * help when one wants to cause substitution failures.  Rather declarations
243  * which have void_t in orthogonal specializations are treated as the same.
244  * For example, assuming the possible `T` types are only allowed to have
245  * either the alias `one` or `two` and never both or none:
246  *
247  *  template <typename T,
248  *            typename std::void_t<std::decay_t<T>::one>* = nullptr>
249  *  void foo(T&&) {}
250  *  template <typename T,
251  *            typename std::void_t<std::decay_t<T>::two>* = nullptr>
252  *  void foo(T&&) {}
253  *
254  * The second foo() will be a redefinition because it conflicts with the first
255  * one; void_t does not cause substitution failures - the template types are
256  * just ignored.
257  */
258 
259 namespace traits_detail {
260 template <class T, class...>
261 struct type_t_ {
262   using type = T;
263 };
264 } // namespace traits_detail
265 
266 template <class T, class... Ts>
267 using type_t = typename traits_detail::type_t_<T, Ts...>::type;
268 template <class... Ts>
269 using void_t = type_t<void, Ts...>;
270 
271 //  nonesuch
272 //
273 //  A tag type which traits may use to indicate lack of a result type.
274 //
275 //  Similar to void in that no values of this type may be constructed. Different
276 //  from void in that no functions may be defined with this return type and no
277 //  complete expressions may evaluate with this expression type.
278 //
279 //  mimic: std::experimental::nonesuch, Library Fundamentals TS v2
280 struct nonesuch {
281   ~nonesuch() = delete;
282   nonesuch(nonesuch const&) = delete;
283   void operator=(nonesuch const&) = delete;
284 };
285 
286 namespace detail {
287 
288 template <typename Void, typename D, template <typename...> class, typename...>
289 struct detected_ {
290   using value_t = std::false_type;
291   using type = D;
292 };
293 template <typename D, template <typename...> class T, typename... A>
294 struct detected_<void_t<T<A...>>, D, T, A...> {
295   using value_t = std::true_type;
296   using type = T<A...>;
297 };
298 
299 } // namespace detail
300 
301 //  detected_or
302 //
303 //  If T<A...> substitutes, has member type alias value_t as std::true_type
304 //  and has member type alias type as T<A...>. Otherwise, has member type
305 //  alias value_t as std::false_type and has member type alias type as D.
306 //
307 //  mimic: std::experimental::detected_or, Library Fundamentals TS v2
308 template <typename D, template <typename...> class T, typename... A>
309 using detected_or = detail::detected_<void, D, T, A...>;
310 
311 //  detected_or_t
312 //
313 //  A trait type alias which results in T<A...> if substitution would succeed
314 //  and in D otherwise.
315 //
316 //  Equivalent to detected_or<D, T, A...>::type.
317 //
318 //  mimic: std::experimental::detected_or_t, Library Fundamentals TS v2
319 template <typename D, template <typename...> class T, typename... A>
320 using detected_or_t = typename detected_or<D, T, A...>::type;
321 
322 //  detected_t
323 //
324 //  A trait type alias which results in T<A...> if substitution would succeed
325 //  and in nonesuch otherwise.
326 //
327 //  Equivalent to detected_or_t<nonesuch, T, A...>.
328 //
329 //  mimic: std::experimental::detected_t, Library Fundamentals TS v2
330 template <template <typename...> class T, typename... A>
331 using detected_t = detected_or_t<nonesuch, T, A...>;
332 
333 //  is_detected_v
334 //  is_detected
335 //
336 //  A trait variable and type to test whether some metafunction from types to
337 //  types would succeed or fail in substitution over a given set of arguments.
338 //
339 //  The trait variable is_detected_v<T, A...> is equivalent to
340 //  detected_or<nonesuch, T, A...>::value_t::value.
341 //  The trait type is_detected<T, A...> unambiguously inherits bool_constant<V>
342 //  where V is is_detected_v<T, A...>.
343 //
344 //  mimic: std::experimental::is_detected, std::experimental::is_detected_v,
345 //    Library Fundamentals TS v2
346 //
347 //  Note: the trait type is_detected differs here by being deferred.
348 template <template <typename...> class T, typename... A>
349 FOLLY_INLINE_VARIABLE constexpr bool is_detected_v =
350     detected_or<nonesuch, T, A...>::value_t::value;
351 template <template <typename...> class T, typename... A>
352 struct is_detected : detected_or<nonesuch, T, A...>::value_t {};
353 
354 template <typename T>
355 using aligned_storage_for_t =
356     typename std::aligned_storage<sizeof(T), alignof(T)>::type;
357 
358 // Older versions of libstdc++ do not provide std::is_trivially_copyable
359 #if defined(__clang__) && !defined(_LIBCPP_VERSION)
360 template <class T>
361 struct is_trivially_copyable : bool_constant<__is_trivially_copyable(T)> {};
362 #else
363 template <class T>
364 using is_trivially_copyable = std::is_trivially_copyable<T>;
365 #endif
366 
367 template <class T>
368 FOLLY_INLINE_VARIABLE constexpr bool is_trivially_copyable_v =
369     is_trivially_copyable<T>::value;
370 
371 /**
372  * IsRelocatable<T>::value describes the ability of moving around
373  * memory a value of type T by using memcpy (as opposed to the
374  * conservative approach of calling the copy constructor and then
375  * destroying the old temporary. Essentially for a relocatable type,
376  * the following two sequences of code should be semantically
377  * equivalent:
378  *
379  * void move1(T * from, T * to) {
380  *   new(to) T(from);
381  *   (*from).~T();
382  * }
383  *
384  * void move2(T * from, T * to) {
385  *   memcpy(to, from, sizeof(T));
386  * }
387  *
388  * Most C++ types are relocatable; the ones that aren't would include
389  * internal pointers or (very rarely) would need to update remote
390  * pointers to pointers tracking them. All C++ primitive types and
391  * type constructors are relocatable.
392  *
393  * This property can be used in a variety of optimizations. Currently
394  * fbvector uses this property intensively.
395  *
396  * The default conservatively assumes the type is not
397  * relocatable. Several specializations are defined for known
398  * types. You may want to add your own specializations. Do so in
399  * namespace folly and make sure you keep the specialization of
400  * IsRelocatable<SomeStruct> in the same header as SomeStruct.
401  *
402  * You may also declare a type to be relocatable by including
403  *    `typedef std::true_type IsRelocatable;`
404  * in the class header.
405  *
406  * It may be unset in a base class by overriding the typedef to false_type.
407  */
408 /*
409  * IsZeroInitializable describes the property that default construction is the
410  * same as memset(dst, 0, sizeof(T)).
411  */
412 
413 namespace traits_detail {
414 
415 #define FOLLY_HAS_TRUE_XXX(name)                                             \
416   template <typename T>                                                      \
417   using detect_##name = typename T::name;                                    \
418   template <class T>                                                         \
419   struct name##_is_true : std::is_same<typename T::name, std::true_type> {}; \
420   template <class T>                                                         \
421   struct has_true_##name : std::conditional<                                 \
422                                is_detected_v<detect_##name, T>,              \
423                                name##_is_true<T>,                            \
424                                std::false_type>::type {}
425 
426 FOLLY_HAS_TRUE_XXX(IsRelocatable);
427 FOLLY_HAS_TRUE_XXX(IsZeroInitializable);
428 
429 #undef FOLLY_HAS_TRUE_XXX
430 
431 } // namespace traits_detail
432 
433 struct Ignore {
434   Ignore() = default;
435   template <class T>
436   constexpr /* implicit */ Ignore(const T&) {}
437   template <class T>
438   const Ignore& operator=(T const&) const {
439     return *this;
440   }
441 };
442 
443 template <class...>
444 using Ignored = Ignore;
445 
446 namespace traits_detail_IsEqualityComparable {
447 Ignore operator==(Ignore, Ignore);
448 
449 template <class T, class U = T>
450 struct IsEqualityComparable
451     : std::is_convertible<
452           decltype(std::declval<T>() == std::declval<U>()),
453           bool> {};
454 } // namespace traits_detail_IsEqualityComparable
455 
456 /* using override */ using traits_detail_IsEqualityComparable::
457     IsEqualityComparable;
458 
459 namespace traits_detail_IsLessThanComparable {
460 Ignore operator<(Ignore, Ignore);
461 
462 template <class T, class U = T>
463 struct IsLessThanComparable
464     : std::is_convertible<
465           decltype(std::declval<T>() < std::declval<U>()),
466           bool> {};
467 } // namespace traits_detail_IsLessThanComparable
468 
469 /* using override */ using traits_detail_IsLessThanComparable::
470     IsLessThanComparable;
471 
472 namespace traits_detail_IsNothrowSwappable {
473 #if defined(__cpp_lib_is_swappable) || (_CPPLIB_VER && _HAS_CXX17)
474 // MSVC already implements the C++17 P0185R1 proposal which adds
475 // std::is_nothrow_swappable, so use it instead if C++17 mode is
476 // enabled.
477 template <typename T>
478 using IsNothrowSwappable = std::is_nothrow_swappable<T>;
479 #elif _CPPLIB_VER
480 // MSVC defines the base even if C++17 is disabled, and MSVC has
481 // issues with our fallback implementation due to over-eager
482 // evaluation of noexcept.
483 template <typename T>
484 using IsNothrowSwappable = std::_Is_nothrow_swappable<T>;
485 #else
486 /* using override */ using std::swap;
487 
488 template <class T>
489 struct IsNothrowSwappable
490     : bool_constant<std::is_nothrow_move_constructible<T>::value&& noexcept(
491           swap(std::declval<T&>(), std::declval<T&>()))> {};
492 #endif
493 } // namespace traits_detail_IsNothrowSwappable
494 
495 /* using override */ using traits_detail_IsNothrowSwappable::IsNothrowSwappable;
496 
497 template <class T>
498 struct IsRelocatable
499     : std::conditional<
500           is_detected_v<traits_detail::detect_IsRelocatable, T>,
501           traits_detail::has_true_IsRelocatable<T>,
502           // TODO add this line (and some tests for it) when we
503           // upgrade to gcc 4.7
504           // std::is_trivially_move_constructible<T>::value ||
505           is_trivially_copyable<T>>::type {};
506 
507 template <class T>
508 struct IsZeroInitializable
509     : std::conditional<
510           is_detected_v<traits_detail::detect_IsZeroInitializable, T>,
511           traits_detail::has_true_IsZeroInitializable<T>,
512           bool_constant<!std::is_class<T>::value>>::type {};
513 
514 namespace detail {
515 template <bool>
516 struct conditional_;
517 template <>
518 struct conditional_<false> {
519   template <typename, typename T>
520   using apply = T;
521 };
522 template <>
523 struct conditional_<true> {
524   template <typename T, typename>
525   using apply = T;
526 };
527 } // namespace detail
528 
529 //  conditional_t
530 //
531 //  Like std::conditional_t but with only two total class template instances,
532 //  rather than as many class template instances as there are uses.
533 //
534 //  As one effect, the result can be used in deducible contexts, allowing
535 //  deduction of conditional_t<V, T, F> to work when T or F is a template param.
536 template <bool V, typename T, typename F>
537 using conditional_t = typename detail::conditional_<V>::template apply<T, F>;
538 
539 template <typename...>
540 struct Conjunction : std::true_type {};
541 template <typename T>
542 struct Conjunction<T> : T {};
543 template <typename T, typename... TList>
544 struct Conjunction<T, TList...>
545     : std::conditional<T::value, Conjunction<TList...>, T>::type {};
546 
547 template <typename...>
548 struct Disjunction : std::false_type {};
549 template <typename T>
550 struct Disjunction<T> : T {};
551 template <typename T, typename... TList>
552 struct Disjunction<T, TList...>
553     : std::conditional<T::value, T, Disjunction<TList...>>::type {};
554 
555 template <typename T>
556 struct Negation : bool_constant<!T::value> {};
557 
558 template <bool... Bs>
559 struct Bools {
560   using valid_type = bool;
561   static constexpr std::size_t size() { return sizeof...(Bs); }
562 };
563 
564 // Lighter-weight than Conjunction, but evaluates all sub-conditions eagerly.
565 template <class... Ts>
566 struct StrictConjunction
567     : std::is_same<Bools<Ts::value...>, Bools<(Ts::value || true)...>> {};
568 
569 template <class... Ts>
570 struct StrictDisjunction
571     : Negation<
572           std::is_same<Bools<Ts::value...>, Bools<(Ts::value && false)...>>> {};
573 
574 namespace detail {
575 template <typename T>
576 using is_transparent_ = typename T::is_transparent;
577 } // namespace detail
578 
579 //  is_transparent_v
580 //  is_transparent
581 //
582 //  A trait variable and type to test whether a less, equal-to, or hash type
583 //  follows the is-transparent protocol used by containers with optional
584 //  heterogeneous access.
585 template <typename T>
586 FOLLY_INLINE_VARIABLE constexpr bool is_transparent_v =
587     is_detected_v<detail::is_transparent_, T>;
588 template <typename T>
589 struct is_transparent : bool_constant<is_transparent_v<T>> {};
590 
591 } // namespace folly
592 
593 /**
594  * Use this macro ONLY inside namespace folly. When using it with a
595  * regular type, use it like this:
596  *
597  * // Make sure you're at namespace ::folly scope
598  * template <> FOLLY_ASSUME_RELOCATABLE(MyType)
599  *
600  * When using it with a template type, use it like this:
601  *
602  * // Make sure you're at namespace ::folly scope
603  * template <class T1, class T2>
604  * FOLLY_ASSUME_RELOCATABLE(MyType<T1, T2>)
605  */
606 #define FOLLY_ASSUME_RELOCATABLE(...) \
607   struct IsRelocatable<__VA_ARGS__> : std::true_type {}
608 
609 /**
610  * The FOLLY_ASSUME_FBVECTOR_COMPATIBLE* macros below encode the
611  * assumption that the type is relocatable per IsRelocatable
612  * above. Many types can be assumed to satisfy this condition, but
613  * it is the responsibility of the user to state that assumption.
614  * User-defined classes will not be optimized for use with
615  * fbvector (see FBVector.h) unless they state that assumption.
616  *
617  * Use FOLLY_ASSUME_FBVECTOR_COMPATIBLE with regular types like this:
618  *
619  * FOLLY_ASSUME_FBVECTOR_COMPATIBLE(MyType)
620  *
621  * The versions FOLLY_ASSUME_FBVECTOR_COMPATIBLE_1, _2, _3, and _4
622  * allow using the macro for describing templatized classes with 1, 2,
623  * 3, and 4 template parameters respectively. For template classes
624  * just use the macro with the appropriate number and pass the name of
625  * the template to it. Example:
626  *
627  * template <class T1, class T2> class MyType { ... };
628  * ...
629  * // Make sure you're at global scope
630  * FOLLY_ASSUME_FBVECTOR_COMPATIBLE_2(MyType)
631  */
632 
633 // Use this macro ONLY at global level (no namespace)
634 #define FOLLY_ASSUME_FBVECTOR_COMPATIBLE(...) \
635   namespace folly {                           \
636   template <>                                 \
637   FOLLY_ASSUME_RELOCATABLE(__VA_ARGS__);      \
638   }
639 // Use this macro ONLY at global level (no namespace)
640 #define FOLLY_ASSUME_FBVECTOR_COMPATIBLE_1(...) \
641   namespace folly {                             \
642   template <class T1>                           \
643   FOLLY_ASSUME_RELOCATABLE(__VA_ARGS__<T1>);    \
644   }
645 // Use this macro ONLY at global level (no namespace)
646 #define FOLLY_ASSUME_FBVECTOR_COMPATIBLE_2(...)  \
647   namespace folly {                              \
648   template <class T1, class T2>                  \
649   FOLLY_ASSUME_RELOCATABLE(__VA_ARGS__<T1, T2>); \
650   }
651 // Use this macro ONLY at global level (no namespace)
652 #define FOLLY_ASSUME_FBVECTOR_COMPATIBLE_3(...)      \
653   namespace folly {                                  \
654   template <class T1, class T2, class T3>            \
655   FOLLY_ASSUME_RELOCATABLE(__VA_ARGS__<T1, T2, T3>); \
656   }
657 // Use this macro ONLY at global level (no namespace)
658 #define FOLLY_ASSUME_FBVECTOR_COMPATIBLE_4(...)          \
659   namespace folly {                                      \
660   template <class T1, class T2, class T3, class T4>      \
661   FOLLY_ASSUME_RELOCATABLE(__VA_ARGS__<T1, T2, T3, T4>); \
662   }
663 
664 namespace folly {
665 
666 // STL commonly-used types
667 template <class T, class U>
668 struct IsRelocatable<std::pair<T, U>>
669     : bool_constant<IsRelocatable<T>::value && IsRelocatable<U>::value> {};
670 
671 // Is T one of T1, T2, ..., Tn?
672 template <typename T, typename... Ts>
673 using IsOneOf = StrictDisjunction<std::is_same<T, Ts>...>;
674 
675 /*
676  * Complementary type traits for integral comparisons.
677  *
678  * For instance, `if(x < 0)` yields an error in clang for unsigned types
679  *  when -Werror is used due to -Wtautological-compare
680  *
681  *
682  * @author: Marcelo Juchem <marcelo@fb.com>
683  */
684 
685 // same as `x < 0`
686 template <typename T>
687 constexpr bool is_negative(T x) {
688   return std::is_signed<T>::value && x < T(0);
689 }
690 
691 // same as `x <= 0`
692 template <typename T>
693 constexpr bool is_non_positive(T x) {
694   return !x || folly::is_negative(x);
695 }
696 
697 // same as `x > 0`
698 template <typename T>
699 constexpr bool is_positive(T x) {
700   return !is_non_positive(x);
701 }
702 
703 // same as `x >= 0`
704 template <typename T>
705 constexpr bool is_non_negative(T x) {
706   return !x || is_positive(x);
707 }
708 
709 namespace detail {
710 
711 // folly::to integral specializations can end up generating code
712 // inside what are really static ifs (not executed because of the templated
713 // types) that violate -Wsign-compare and/or -Wbool-compare so suppress them
714 // in order to not prevent all calling code from using it.
715 FOLLY_PUSH_WARNING
716 FOLLY_GNU_DISABLE_WARNING("-Wsign-compare")
717 FOLLY_GCC_DISABLE_WARNING("-Wbool-compare")
718 FOLLY_MSVC_DISABLE_WARNING(4287) // unsigned/negative constant mismatch
719 FOLLY_MSVC_DISABLE_WARNING(4388) // sign-compare
720 FOLLY_MSVC_DISABLE_WARNING(4804) // bool-compare
721 
722 template <typename RHS, RHS rhs, typename LHS>
723 bool less_than_impl(LHS const lhs) {
724   // clang-format off
725   return
726       // Ensure signed and unsigned values won't be compared directly.
727       (!std::is_signed<RHS>::value && is_negative(lhs)) ? true :
728       (!std::is_signed<LHS>::value && is_negative(rhs)) ? false :
729       rhs > std::numeric_limits<LHS>::max() ? true :
730       rhs <= std::numeric_limits<LHS>::lowest() ? false :
731       lhs < rhs;
732   // clang-format on
733 }
734 
735 template <typename RHS, RHS rhs, typename LHS>
736 bool greater_than_impl(LHS const lhs) {
737   // clang-format off
738   return
739       // Ensure signed and unsigned values won't be compared directly.
740       (!std::is_signed<RHS>::value && is_negative(lhs)) ? false :
741       (!std::is_signed<LHS>::value && is_negative(rhs)) ? true :
742       rhs > std::numeric_limits<LHS>::max() ? false :
743       rhs < std::numeric_limits<LHS>::lowest() ? true :
744       lhs > rhs;
745   // clang-format on
746 }
747 
748 FOLLY_POP_WARNING
749 
750 } // namespace detail
751 
752 template <typename RHS, RHS rhs, typename LHS>
753 bool less_than(LHS const lhs) {
754   return detail::
755       less_than_impl<RHS, rhs, typename std::remove_reference<LHS>::type>(lhs);
756 }
757 
758 template <typename RHS, RHS rhs, typename LHS>
759 bool greater_than(LHS const lhs) {
760   return detail::
761       greater_than_impl<RHS, rhs, typename std::remove_reference<LHS>::type>(
762           lhs);
763 }
764 } // namespace folly
765 
766 // Assume nothing when compiling with MSVC.
767 #ifndef _MSC_VER
768 FOLLY_ASSUME_FBVECTOR_COMPATIBLE_2(std::unique_ptr)
769 FOLLY_ASSUME_FBVECTOR_COMPATIBLE_1(std::shared_ptr)
770 #endif
771 
772 namespace folly {
773 
774 //  Some compilers have signed __int128 and unsigned __int128 types, and some
775 //  libraries with some compilers have traits for those types. It's a mess.
776 //  Import things into folly and then fill in whatever is missing.
777 //
778 //  The aliases:
779 //    int128_t
780 //    uint128_t
781 //
782 //  The traits:
783 //    is_arithmetic
784 //    is_arithmetic_v
785 //    is_integral
786 //    is_integral_v
787 //    is_signed
788 //    is_signed_v
789 //    is_unsigned
790 //    is_unsigned_v
791 //    make_signed
792 //    make_signed_t
793 //    make_unsigned
794 //    make_unsigned_t
795 
796 template <typename T>
797 struct is_arithmetic : std::is_arithmetic<T> {};
798 template <typename T>
799 FOLLY_INLINE_VARIABLE constexpr bool is_arithmetic_v = is_arithmetic<T>::value;
800 
801 template <typename T>
802 struct is_integral : std::is_integral<T> {};
803 template <typename T>
804 FOLLY_INLINE_VARIABLE constexpr bool is_integral_v = is_integral<T>::value;
805 
806 template <typename T>
807 struct is_signed : std::is_signed<T> {};
808 template <typename T>
809 FOLLY_INLINE_VARIABLE constexpr bool is_signed_v = is_signed<T>::value;
810 
811 template <typename T>
812 struct is_unsigned : std::is_unsigned<T> {};
813 template <typename T>
814 FOLLY_INLINE_VARIABLE constexpr bool is_unsigned_v = is_unsigned<T>::value;
815 
816 template <typename T>
817 struct make_signed : std::make_signed<T> {};
818 template <typename T>
819 using make_signed_t = typename make_signed<T>::type;
820 
821 template <typename T>
822 struct make_unsigned : std::make_unsigned<T> {};
823 template <typename T>
824 using make_unsigned_t = typename make_unsigned<T>::type;
825 
826 #if FOLLY_HAVE_INT128_T
827 
828 using int128_t = signed __int128;
829 using uint128_t = unsigned __int128;
830 
831 template <>
832 struct is_arithmetic<int128_t> : std::true_type {};
833 template <>
834 struct is_arithmetic<uint128_t> : std::true_type {};
835 
836 template <>
837 struct is_integral<int128_t> : std::true_type {};
838 template <>
839 struct is_integral<uint128_t> : std::true_type {};
840 
841 template <>
842 struct is_signed<int128_t> : std::true_type {};
843 template <>
844 struct is_signed<uint128_t> : std::false_type {};
845 template <>
846 struct is_unsigned<int128_t> : std::false_type {};
847 template <>
848 struct is_unsigned<uint128_t> : std::true_type {};
849 
850 template <>
851 struct make_signed<int128_t> {
852   using type = int128_t;
853 };
854 template <>
855 struct make_signed<uint128_t> {
856   using type = int128_t;
857 };
858 
859 template <>
860 struct make_unsigned<int128_t> {
861   using type = uint128_t;
862 };
863 template <>
864 struct make_unsigned<uint128_t> {
865   using type = uint128_t;
866 };
867 #endif // FOLLY_HAVE_INT128_T
868 
869 } // namespace folly
870