blob: 7af9f983eded05264705d178ec944133b25d73ed [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"
Felix Thomasmathibalanafd38f02023-09-27 17:46:17 +010029
Sang-Hoon Park68dd25f2020-10-19 16:00:11 +010030#include "support/Rounding.h"
Georgios Pinitas303f0db2018-11-19 11:56:51 +000031
32namespace arm_compute
33{
34namespace utils
35{
36namespace cast
37{
38// *INDENT-OFF*
39// clang-format off
40// same type
41template<typename T,
42 typename U,
43 typename std::enable_if<std::is_same<T, U>::value, int >::type = 0 >
44T saturate_cast(U v)
45{
46 return v;
47}
48
49// signed -> signed widening/same_width
50template<typename T,
51 typename U,
52 typename std::enable_if<std::is_integral<T>::value &&
53 std::is_integral<U>::value &&
54 std::is_signed<U>() &&
55 std::is_signed<T>() &&
56 !std::is_same<T, U>::value &&
57 sizeof(T) >= sizeof(U),
58 int >::type = 0 >
59inline T saturate_cast(U v)
60{
61 return static_cast<T>(v);
62}
63// signed -> signed narrowing
64template<typename T,
65 typename U,
66 typename std::enable_if<std::is_integral<T>::value &&
67 std::is_integral<U>::value &&
68 std::is_signed<U>() &&
69 std::is_signed<T>() &&
70 !std::is_same<T, U>::value &&
71 sizeof(T) < sizeof(U),
72 int >::type = 0 >
73inline T saturate_cast(U v)
74{
75 return static_cast<T>(utility::clamp<U>(v, std::numeric_limits<T>::lowest(), std::numeric_limits<T>::max()));
76}
77
78// unsigned -> signed widening
79template<typename T,
80 typename U,
81 typename std::enable_if<std::is_integral<T>::value &&
82 std::is_integral<U>::value &&
83 std::is_unsigned<U>() &&
84 std::is_signed<T>() &&
85 !std::is_same<T, U>::value &&
86 (sizeof(T) > sizeof(U)),
87 int >::type = 0 >
88inline T saturate_cast(U v)
89{
90 return static_cast<T>(v);
91}
92// unsigned -> signed narrowing
93template<typename T,
94 typename U,
95 typename std::enable_if<std::is_integral<T>::value &&
96 std::is_integral<U>::value &&
97 std::is_unsigned<U>() &&
98 std::is_signed<T>() &&
99 !std::is_same<T, U>::value &&
100 sizeof(T) < sizeof(U),
101 int >::type = 0 >
102inline T saturate_cast(U v)
103{
104 return static_cast<T>(std::min<U>(v, std::numeric_limits<T>::max()));
105}
106// unsigned -> signed same_width
107template<typename T,
108 typename U,
109 typename std::enable_if<std::is_integral<T>::value &&
110 std::is_integral<U>::value &&
111 std::is_unsigned<U>() &&
112 std::is_signed<T>() &&
113 !std::is_same<T, U>::value &&
114 sizeof(T) == sizeof(U),
115 int >::type = 0 >
116inline T saturate_cast(U v)
117{
118 return static_cast<T>(std::min<U>(v, std::numeric_limits<T>::max()));
119}
120
121// signed -> unsigned widening/same width
122template<typename T,
123 typename U,
124 typename std::enable_if<std::is_integral<T>::value &&
125 std::is_integral<U>::value &&
126 std::is_signed<U>() &&
127 std::is_unsigned<T>() &&
128 !std::is_same<T, U>::value &&
129 sizeof(T) >= sizeof(U),
130 int >::type = 0 >
131inline T saturate_cast(U v)
132{
133 return static_cast<T>(std::max<U>(0, v));
134}
135
136// signed -> unsigned narrowing
137template<typename T,
138 typename U,
139 typename std::enable_if<std::is_integral<T>::value &&
140 std::is_integral<U>::value &&
141 std::is_signed<U>() &&
142 std::is_unsigned<T>() &&
143 !std::is_same<T, U>::value &&
144 sizeof(T) < sizeof(U),
145 int >::type = 0 >
146inline T saturate_cast(U v)
147{
148 return static_cast<T>(utility::clamp<U>(v, 0, std::numeric_limits<T>::max()));
149}
150
151// unsigned -> unsigned widening/same width
152template<typename T,
153 typename U,
154 typename std::enable_if<std::is_integral<T>::value &&
155 std::is_integral<U>::value &&
156 std::is_unsigned<T>() &&
157 std::is_unsigned<U>() &&
158 !std::is_same<T, U>::value &&
159 sizeof(T) >= sizeof(U),
160 int >::type = 0 >
161inline T saturate_cast(U v)
162{
163 return static_cast<T>(v);
164}
165
166// unsigned -> unsigned narrowing
167template<typename T,
168 typename U,
169 typename std::enable_if<std::is_integral<T>::value &&
170 std::is_integral<U>::value &&
171 std::is_unsigned<T>() &&
172 std::is_unsigned<U>() &&
173 !std::is_same<T, U>::value &&
174 sizeof(T) < sizeof(U),
175 int >::type = 0 >
176inline T saturate_cast(U v)
177{
178 return static_cast<T>(utility::clamp<U>(v, std::numeric_limits<T>::lowest(), std::numeric_limits<T>::max()));
179}
180
181// float -> int
182template<typename T,
183 typename U,
184 typename std::enable_if<std::is_integral<T>::value &&
185 traits::is_floating_point<U>::value,
186 int >::type = 0 >
187inline T saturate_cast(U v)
188{
189 int32_t vi = utils::rounding::round_half_away_from_zero(v);
190 return saturate_cast<T>(vi);
191}
192
193// int -> float
194template<typename T,
195 typename U,
196 typename std::enable_if<traits::is_floating_point<T>::value &&
197 std::is_integral<U>::value,
198 int >::type = 0 >
199inline T saturate_cast(U v)
200{
201 return static_cast<T>(v);
202}
203
204// float -> float
205template<typename T,
206 typename U,
207 typename std::enable_if<traits::is_floating_point<T>::value &&
208 traits::is_floating_point<U>::value,
209 int >::type = 0 >
210inline T saturate_cast(U v)
211{
212 return static_cast<T>(v);
213}
214// clang-format on
215// *INDENT-ON*
216} // namespace cast
217} // namespace utils
218} // namespace arm_compute
Michalis Spyrouf4643372019-11-29 16:17:13 +0000219#endif /* ARM_COMPUTE_UTILS_CAST_SATURATE_CAST_H */