1#pragma once
2
3#include <c10/macros/Macros.h>
4#include <limits>
5#include <type_traits>
6
7C10_CLANG_DIAGNOSTIC_PUSH()
8#if C10_CLANG_HAS_WARNING("-Wstring-conversion")
9C10_CLANG_DIAGNOSTIC_IGNORE("-Wstring-conversion")
10#endif
11#if C10_CLANG_HAS_WARNING("-Wimplicit-int-float-conversion")
12C10_CLANG_DIAGNOSTIC_IGNORE("-Wimplicit-int-float-conversion")
13#endif
14
15namespace c10 {
16
17/// Returns false since we cannot have x < 0 if x is unsigned.
18template <typename T>
19static inline constexpr bool is_negative(
20 const T& /*x*/,
21 std::true_type /*is_unsigned*/) {
22 return false;
23}
24
25/// Returns true if a signed variable x < 0
26template <typename T>
27static inline constexpr bool is_negative(
28 const T& x,
29 std::false_type /*is_unsigned*/) {
30 return x < T(0);
31}
32
33/// Returns true if x < 0
34/// NOTE: Will fail on an unsigned custom type
35/// For the most part it's possible to fix this if
36/// the custom type has a constexpr constructor.
37/// However, notably, c10::Half does not :-(
38template <typename T>
39inline constexpr bool is_negative(const T& x) {
40 return is_negative(x, std::is_unsigned<T>());
41}
42
43/// Returns the sign of an unsigned variable x as 0, 1
44template <typename T>
45static inline constexpr int signum(const T& x, std::true_type /*is_unsigned*/) {
46 return T(0) < x;
47}
48
49/// Returns the sign of a signed variable x as -1, 0, 1
50template <typename T>
51static inline constexpr int signum(
52 const T& x,
53 std::false_type /*is_unsigned*/) {
54 return (T(0) < x) - (x < T(0));
55}
56
57/// Returns the sign of x as -1, 0, 1
58/// NOTE: Will fail on an unsigned custom type
59/// For the most part it's possible to fix this if
60/// the custom type has a constexpr constructor.
61/// However, notably, c10::Half does not :-(
62template <typename T>
63inline constexpr int signum(const T& x) {
64 return signum(x, std::is_unsigned<T>());
65}
66
67/// Returns true if a and b are not both negative
68template <typename T, typename U>
69inline constexpr bool signs_differ(const T& a, const U& b) {
70 return is_negative(a) != is_negative(b);
71}
72
73// Suppress sign compare warning when compiling with GCC
74// as later does not account for short-circuit rule before
75// raising the warning, see https://godbolt.org/z/Tr3Msnz99
76#ifdef __GNUC__
77#pragma GCC diagnostic push
78#pragma GCC diagnostic ignored "-Wsign-compare"
79#endif
80
81/// Returns true if x is greater than the greatest value of the type Limit
82template <typename Limit, typename T>
83inline constexpr bool greater_than_max(const T& x) {
84 constexpr bool can_overflow =
85 std::numeric_limits<T>::digits > std::numeric_limits<Limit>::digits;
86 return can_overflow && x > std::numeric_limits<Limit>::max();
87}
88
89#ifdef __GNUC__
90#pragma GCC diagnostic pop
91#endif
92
93/// Returns true if x < lowest(Limit). Standard comparison
94template <typename Limit, typename T>
95static inline constexpr bool less_than_lowest(
96 const T& x,
97 std::false_type /*limit_is_unsigned*/,
98 std::false_type /*x_is_unsigned*/) {
99 return x < std::numeric_limits<Limit>::lowest();
100}
101
102/// Returns false since all the limit is signed and therefore includes
103/// negative values but x cannot be negative because it is unsigned
104template <typename Limit, typename T>
105static inline constexpr bool less_than_lowest(
106 const T& /*x*/,
107 std::false_type /*limit_is_unsigned*/,
108 std::true_type /*x_is_unsigned*/) {
109 return false;
110}
111
112/// Returns true if x < 0, where 0 is constructed from T.
113/// Limit is not signed, so its lower value is zero
114template <typename Limit, typename T>
115static inline constexpr bool less_than_lowest(
116 const T& x,
117 std::true_type /*limit_is_unsigned*/,
118 std::false_type /*x_is_unsigned*/) {
119 return x < T(0);
120}
121
122/// Returns false sign both types are unsigned
123template <typename Limit, typename T>
124static inline constexpr bool less_than_lowest(
125 const T& /*x*/,
126 std::true_type /*limit_is_unsigned*/,
127 std::true_type /*x_is_unsigned*/) {
128 return false;
129}
130
131/// Returns true if x is less than the lowest value of type T
132/// NOTE: Will fail on an unsigned custom type
133/// For the most part it's possible to fix this if
134/// the custom type has a constexpr constructor.
135/// However, notably, c10::Half does not :
136template <typename Limit, typename T>
137inline constexpr bool less_than_lowest(const T& x) {
138 return less_than_lowest<Limit>(
139 x, std::is_unsigned<Limit>(), std::is_unsigned<T>());
140}
141
142} // namespace c10
143
144C10_CLANG_DIAGNOSTIC_POP()
145