ylimits.h 2.4 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192
  1. #pragma once
  2. #include <limits>
  3. #if defined(max) || defined(min)
  4. #error "stop defining 'min' and 'max' macros, evil people"
  5. #endif
  6. template <class T>
  7. static constexpr T Max() noexcept {
  8. return std::numeric_limits<T>::max();
  9. }
  10. template <class T>
  11. static constexpr T Min() noexcept {
  12. return std::numeric_limits<T>::min();
  13. }
  14. namespace NPrivate {
  15. struct TMax {
  16. template <class T>
  17. constexpr operator T() const {
  18. return Max<T>();
  19. }
  20. };
  21. struct TMin {
  22. template <class T>
  23. constexpr operator T() const {
  24. return Min<T>();
  25. }
  26. };
  27. }
  28. static constexpr ::NPrivate::TMax Max() noexcept {
  29. return {};
  30. }
  31. static constexpr ::NPrivate::TMin Min() noexcept {
  32. return {};
  33. }
  34. namespace NPrivate {
  35. template <unsigned long long N>
  36. static constexpr double MaxFloorValue() {
  37. return N;
  38. }
  39. template <unsigned long long N>
  40. static constexpr double MaxCeilValue() {
  41. return N;
  42. }
  43. template <>
  44. constexpr double MaxFloorValue<0x7FFF'FFFF'FFFF'FFFFull>() {
  45. return 9223372036854774784.0; // 0x7FFFFFFFFFFFFC00p0
  46. }
  47. template <>
  48. constexpr double MaxCeilValue<0x7FFF'FFFF'FFFF'FFFFull>() {
  49. return 9223372036854775808.0; // 0x8000000000000000p0
  50. }
  51. template <>
  52. constexpr double MaxFloorValue<0xFFFF'FFFF'FFFF'FFFFull>() {
  53. return 18446744073709549568.0; // 0xFFFFFFFFFFFFF800p0
  54. }
  55. template <>
  56. constexpr double MaxCeilValue<0xFFFF'FFFF'FFFF'FFFFull>() {
  57. return 18446744073709551616.0; // 0x10000000000000000p0
  58. }
  59. }
  60. // MaxFloor<T> is the greatest double within the range of T.
  61. //
  62. // 1. If Max<T> is an exact double, MaxFloor<T> = Max<T> = MaxCeil<T>.
  63. // In this case some doubles above MaxFloor<T> cast to T may round
  64. // to Max<T> depending on the rounding mode.
  65. //
  66. // 2. Otherwise Max<T> is between MaxFloor<T> and MaxCeil<T>, and
  67. // MaxFloor<T> is the largest double that does not overflow T.
  68. template <class T>
  69. static constexpr double MaxFloor() noexcept {
  70. return ::NPrivate::MaxFloorValue<Max<T>()>();
  71. }
  72. // MaxCeil<T> is the smallest double not lesser than Max<T>.
  73. //
  74. // 1. If Max<T> is an exact double, MaxCeil<T> = Max<T> = MaxFloor<T>.
  75. //
  76. // 2. Otherwise Max<T> is between MaxFloor<T> and MaxCeil<T>, and
  77. // MaxCeil<T> is the smallest double that overflows T.
  78. template <class T>
  79. static constexpr double MaxCeil() noexcept {
  80. return ::NPrivate::MaxCeilValue<Max<T>()>();
  81. }