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