blob: a9982d8e969c1a6fb6f8015f89b867dc0d72f031 [file] [log] [blame]
Georgios Pinitas303f0db2018-11-19 11:56:51 +00001/*
Sang-Hoon Park68dd25f2020-10-19 16:00:11 +01002 * Copyright (c) 2018-2020 Arm Limited.
Georgios Pinitas303f0db2018-11-19 11:56:51 +00003 *
4 * SPDX-License-Identifier: MIT
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to
8 * deal in the Software without restriction, including without limitation the
9 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10 * sell copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in all
14 * copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 * SOFTWARE.
23 */
Michalis Spyrouf4643372019-11-29 16:17:13 +000024#ifndef ARM_COMPUTE_UTILS_CAST_SATURATE_CAST_H
25#define ARM_COMPUTE_UTILS_CAST_SATURATE_CAST_H
Georgios Pinitas303f0db2018-11-19 11:56:51 +000026
Georgios Pinitas303f0db2018-11-19 11:56:51 +000027#include "arm_compute/core/utils/misc/Traits.h"
28#include "arm_compute/core/utils/misc/Utility.h"
Sang-Hoon Park68dd25f2020-10-19 16:00:11 +010029#include "support/Rounding.h"
Georgios Pinitas303f0db2018-11-19 11:56:51 +000030
31namespace arm_compute
32{
33namespace utils
34{
35namespace cast
36{
37// *INDENT-OFF*
38// clang-format off
39// same type
40template<typename T,
41 typename U,
42 typename std::enable_if<std::is_same<T, U>::value, int >::type = 0 >
43T saturate_cast(U v)
44{
45 return v;
46}
47
48// signed -> signed widening/same_width
49template<typename T,
50 typename U,
51 typename std::enable_if<std::is_integral<T>::value &&
52 std::is_integral<U>::value &&
53 std::is_signed<U>() &&
54 std::is_signed<T>() &&
55 !std::is_same<T, U>::value &&
56 sizeof(T) >= sizeof(U),
57 int >::type = 0 >
58inline T saturate_cast(U v)
59{
60 return static_cast<T>(v);
61}
62// signed -> signed narrowing
63template<typename T,
64 typename U,
65 typename std::enable_if<std::is_integral<T>::value &&
66 std::is_integral<U>::value &&
67 std::is_signed<U>() &&
68 std::is_signed<T>() &&
69 !std::is_same<T, U>::value &&
70 sizeof(T) < sizeof(U),
71 int >::type = 0 >
72inline T saturate_cast(U v)
73{
74 return static_cast<T>(utility::clamp<U>(v, std::numeric_limits<T>::lowest(), std::numeric_limits<T>::max()));
75}
76
77// unsigned -> signed widening
78template<typename T,
79 typename U,
80 typename std::enable_if<std::is_integral<T>::value &&
81 std::is_integral<U>::value &&
82 std::is_unsigned<U>() &&
83 std::is_signed<T>() &&
84 !std::is_same<T, U>::value &&
85 (sizeof(T) > sizeof(U)),
86 int >::type = 0 >
87inline T saturate_cast(U v)
88{
89 return static_cast<T>(v);
90}
91// unsigned -> signed narrowing
92template<typename T,
93 typename U,
94 typename std::enable_if<std::is_integral<T>::value &&
95 std::is_integral<U>::value &&
96 std::is_unsigned<U>() &&
97 std::is_signed<T>() &&
98 !std::is_same<T, U>::value &&
99 sizeof(T) < sizeof(U),
100 int >::type = 0 >
101inline T saturate_cast(U v)
102{
103 return static_cast<T>(std::min<U>(v, std::numeric_limits<T>::max()));
104}
105// unsigned -> signed same_width
106template<typename T,
107 typename U,
108 typename std::enable_if<std::is_integral<T>::value &&
109 std::is_integral<U>::value &&
110 std::is_unsigned<U>() &&
111 std::is_signed<T>() &&
112 !std::is_same<T, U>::value &&
113 sizeof(T) == sizeof(U),
114 int >::type = 0 >
115inline T saturate_cast(U v)
116{
117 return static_cast<T>(std::min<U>(v, std::numeric_limits<T>::max()));
118}
119
120// signed -> unsigned widening/same width
121template<typename T,
122 typename U,
123 typename std::enable_if<std::is_integral<T>::value &&
124 std::is_integral<U>::value &&
125 std::is_signed<U>() &&
126 std::is_unsigned<T>() &&
127 !std::is_same<T, U>::value &&
128 sizeof(T) >= sizeof(U),
129 int >::type = 0 >
130inline T saturate_cast(U v)
131{
132 return static_cast<T>(std::max<U>(0, v));
133}
134
135// signed -> unsigned narrowing
136template<typename T,
137 typename U,
138 typename std::enable_if<std::is_integral<T>::value &&
139 std::is_integral<U>::value &&
140 std::is_signed<U>() &&
141 std::is_unsigned<T>() &&
142 !std::is_same<T, U>::value &&
143 sizeof(T) < sizeof(U),
144 int >::type = 0 >
145inline T saturate_cast(U v)
146{
147 return static_cast<T>(utility::clamp<U>(v, 0, std::numeric_limits<T>::max()));
148}
149
150// unsigned -> unsigned widening/same width
151template<typename T,
152 typename U,
153 typename std::enable_if<std::is_integral<T>::value &&
154 std::is_integral<U>::value &&
155 std::is_unsigned<T>() &&
156 std::is_unsigned<U>() &&
157 !std::is_same<T, U>::value &&
158 sizeof(T) >= sizeof(U),
159 int >::type = 0 >
160inline T saturate_cast(U v)
161{
162 return static_cast<T>(v);
163}
164
165// unsigned -> unsigned narrowing
166template<typename T,
167 typename U,
168 typename std::enable_if<std::is_integral<T>::value &&
169 std::is_integral<U>::value &&
170 std::is_unsigned<T>() &&
171 std::is_unsigned<U>() &&
172 !std::is_same<T, U>::value &&
173 sizeof(T) < sizeof(U),
174 int >::type = 0 >
175inline T saturate_cast(U v)
176{
177 return static_cast<T>(utility::clamp<U>(v, std::numeric_limits<T>::lowest(), std::numeric_limits<T>::max()));
178}
179
180// float -> int
181template<typename T,
182 typename U,
183 typename std::enable_if<std::is_integral<T>::value &&
184 traits::is_floating_point<U>::value,
185 int >::type = 0 >
186inline T saturate_cast(U v)
187{
188 int32_t vi = utils::rounding::round_half_away_from_zero(v);
189 return saturate_cast<T>(vi);
190}
191
192// int -> float
193template<typename T,
194 typename U,
195 typename std::enable_if<traits::is_floating_point<T>::value &&
196 std::is_integral<U>::value,
197 int >::type = 0 >
198inline T saturate_cast(U v)
199{
200 return static_cast<T>(v);
201}
202
203// float -> float
204template<typename T,
205 typename U,
206 typename std::enable_if<traits::is_floating_point<T>::value &&
207 traits::is_floating_point<U>::value,
208 int >::type = 0 >
209inline T saturate_cast(U v)
210{
211 return static_cast<T>(v);
212}
213// clang-format on
214// *INDENT-ON*
215} // namespace cast
216} // namespace utils
217} // namespace arm_compute
Michalis Spyrouf4643372019-11-29 16:17:13 +0000218#endif /* ARM_COMPUTE_UTILS_CAST_SATURATE_CAST_H */