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