xref: /aosp_15_r20/external/armnn/profiling/common/include/NumericCast.hpp (revision 89c4ff92f2867872bb9e2354d150bf0c8c502810)
1*89c4ff92SAndroid Build Coastguard Worker //
2*89c4ff92SAndroid Build Coastguard Worker // Copyright © 2020 Arm Ltd and Contributors. All rights reserved.
3*89c4ff92SAndroid Build Coastguard Worker // SPDX-License-Identifier: MIT
4*89c4ff92SAndroid Build Coastguard Worker //
5*89c4ff92SAndroid Build Coastguard Worker 
6*89c4ff92SAndroid Build Coastguard Worker #pragma once
7*89c4ff92SAndroid Build Coastguard Worker 
8*89c4ff92SAndroid Build Coastguard Worker #include "Assert.hpp"
9*89c4ff92SAndroid Build Coastguard Worker 
10*89c4ff92SAndroid Build Coastguard Worker #include <type_traits>
11*89c4ff92SAndroid Build Coastguard Worker #include <limits>
12*89c4ff92SAndroid Build Coastguard Worker 
13*89c4ff92SAndroid Build Coastguard Worker namespace arm
14*89c4ff92SAndroid Build Coastguard Worker {
15*89c4ff92SAndroid Build Coastguard Worker 
16*89c4ff92SAndroid Build Coastguard Worker namespace pipe
17*89c4ff92SAndroid Build Coastguard Worker {
18*89c4ff92SAndroid Build Coastguard Worker 
19*89c4ff92SAndroid Build Coastguard Worker #if !defined(NDEBUG) || defined(ARM_PIPE_NUMERIC_CAST_TESTABLE)
20*89c4ff92SAndroid Build Coastguard Worker #define ENABLE_NUMERIC_CAST_CHECKS 1
21*89c4ff92SAndroid Build Coastguard Worker #else
22*89c4ff92SAndroid Build Coastguard Worker #define ENABLE_NUMERIC_CAST_CHECKS 0
23*89c4ff92SAndroid Build Coastguard Worker #endif
24*89c4ff92SAndroid Build Coastguard Worker 
25*89c4ff92SAndroid Build Coastguard Worker #if defined(ARM_PIPE_NUMERIC_CAST_TESTABLE)
26*89c4ff92SAndroid Build Coastguard Worker #   define ARM_PIPE_NUMERIC_CAST_CHECK(cond, msg) ConditionalThrow<std::bad_cast>(cond)
27*89c4ff92SAndroid Build Coastguard Worker #else
28*89c4ff92SAndroid Build Coastguard Worker #   define ARM_PIPE_NUMERIC_CAST_CHECK(cond, msg) ARM_PIPE_ASSERT_MSG(cond, msg)
29*89c4ff92SAndroid Build Coastguard Worker #endif
30*89c4ff92SAndroid Build Coastguard Worker 
31*89c4ff92SAndroid Build Coastguard Worker template<typename Dest, typename Source>
32*89c4ff92SAndroid Build Coastguard Worker typename std::enable_if_t<
33*89c4ff92SAndroid Build Coastguard Worker     std::is_unsigned<Source>::value &&
34*89c4ff92SAndroid Build Coastguard Worker     std::is_unsigned<Dest>::value
35*89c4ff92SAndroid Build Coastguard Worker     , Dest>
numeric_cast(Source source)36*89c4ff92SAndroid Build Coastguard Worker numeric_cast(Source source)
37*89c4ff92SAndroid Build Coastguard Worker {
38*89c4ff92SAndroid Build Coastguard Worker #if ENABLE_NUMERIC_CAST_CHECKS
39*89c4ff92SAndroid Build Coastguard Worker     if (source > std::numeric_limits<Dest>::max())
40*89c4ff92SAndroid Build Coastguard Worker     {
41*89c4ff92SAndroid Build Coastguard Worker         ARM_PIPE_NUMERIC_CAST_CHECK(false, "numeric_cast failed casting unsigned type to "
42*89c4ff92SAndroid Build Coastguard Worker                                         "narrower unsigned type. Overflow detected.");
43*89c4ff92SAndroid Build Coastguard Worker     }
44*89c4ff92SAndroid Build Coastguard Worker #endif // ENABLE_NUMERIC_CAST_CHECKS
45*89c4ff92SAndroid Build Coastguard Worker 
46*89c4ff92SAndroid Build Coastguard Worker     return static_cast<Dest>(source);
47*89c4ff92SAndroid Build Coastguard Worker }
48*89c4ff92SAndroid Build Coastguard Worker 
49*89c4ff92SAndroid Build Coastguard Worker template<typename Dest, typename Source>
50*89c4ff92SAndroid Build Coastguard Worker typename std::enable_if_t<
51*89c4ff92SAndroid Build Coastguard Worker     std::is_signed<Source>::value &&
52*89c4ff92SAndroid Build Coastguard Worker     std::is_signed<Dest>::value
53*89c4ff92SAndroid Build Coastguard Worker     , Dest>
numeric_cast(Source source)54*89c4ff92SAndroid Build Coastguard Worker numeric_cast(Source source)
55*89c4ff92SAndroid Build Coastguard Worker {
56*89c4ff92SAndroid Build Coastguard Worker     static_assert(!std::is_floating_point<Source>::value && !std::is_floating_point<Dest>::value,
57*89c4ff92SAndroid Build Coastguard Worker         "numeric_cast doesn't cast float.");
58*89c4ff92SAndroid Build Coastguard Worker 
59*89c4ff92SAndroid Build Coastguard Worker #if ENABLE_NUMERIC_CAST_CHECKS
60*89c4ff92SAndroid Build Coastguard Worker     if (source > std::numeric_limits<Dest>::max())
61*89c4ff92SAndroid Build Coastguard Worker     {
62*89c4ff92SAndroid Build Coastguard Worker         ARM_PIPE_NUMERIC_CAST_CHECK(false, "numeric_cast failed casting signed type to narrower signed type. "
63*89c4ff92SAndroid Build Coastguard Worker                                         "Overflow detected.");
64*89c4ff92SAndroid Build Coastguard Worker     }
65*89c4ff92SAndroid Build Coastguard Worker 
66*89c4ff92SAndroid Build Coastguard Worker     if (source < std::numeric_limits<Dest>::lowest())
67*89c4ff92SAndroid Build Coastguard Worker     {
68*89c4ff92SAndroid Build Coastguard Worker         ARM_PIPE_NUMERIC_CAST_CHECK(false, "numeric_cast failed casting signed type to narrower signed type. "
69*89c4ff92SAndroid Build Coastguard Worker                                         "Underflow detected.");
70*89c4ff92SAndroid Build Coastguard Worker     }
71*89c4ff92SAndroid Build Coastguard Worker #endif // ENABLE_NUMERIC_CAST_CHECKS
72*89c4ff92SAndroid Build Coastguard Worker 
73*89c4ff92SAndroid Build Coastguard Worker     return static_cast<Dest>(source);
74*89c4ff92SAndroid Build Coastguard Worker }
75*89c4ff92SAndroid Build Coastguard Worker 
76*89c4ff92SAndroid Build Coastguard Worker // numeric cast from unsigned to signed checked for narrowing overflows
77*89c4ff92SAndroid Build Coastguard Worker template<typename Dest, typename Source>
78*89c4ff92SAndroid Build Coastguard Worker typename std::enable_if_t<
79*89c4ff92SAndroid Build Coastguard Worker     std::is_signed<Dest>::value &&
80*89c4ff92SAndroid Build Coastguard Worker     std::is_unsigned<Source>::value
81*89c4ff92SAndroid Build Coastguard Worker     , Dest>
numeric_cast(Source sValue)82*89c4ff92SAndroid Build Coastguard Worker numeric_cast(Source sValue)
83*89c4ff92SAndroid Build Coastguard Worker {
84*89c4ff92SAndroid Build Coastguard Worker     static_assert(!std::is_floating_point<Dest>::value, "numeric_cast doesn't cast to float.");
85*89c4ff92SAndroid Build Coastguard Worker 
86*89c4ff92SAndroid Build Coastguard Worker #if ENABLE_NUMERIC_CAST_CHECKS
87*89c4ff92SAndroid Build Coastguard Worker     if (sValue > static_cast< typename std::make_unsigned<Dest>::type >(std::numeric_limits<Dest>::max()))
88*89c4ff92SAndroid Build Coastguard Worker     {
89*89c4ff92SAndroid Build Coastguard Worker         ARM_PIPE_NUMERIC_CAST_CHECK(false, "numeric_cast failed casting unsigned type to signed type. "
90*89c4ff92SAndroid Build Coastguard Worker                                         "Overflow detected.");
91*89c4ff92SAndroid Build Coastguard Worker     }
92*89c4ff92SAndroid Build Coastguard Worker #endif // ENABLE_NUMERIC_CAST_CHECKS
93*89c4ff92SAndroid Build Coastguard Worker 
94*89c4ff92SAndroid Build Coastguard Worker     return static_cast<Dest>(sValue);
95*89c4ff92SAndroid Build Coastguard Worker }
96*89c4ff92SAndroid Build Coastguard Worker 
97*89c4ff92SAndroid Build Coastguard Worker // numeric cast from signed to unsigned checked for underflows and narrowing overflows
98*89c4ff92SAndroid Build Coastguard Worker template<typename Dest, typename Source>
99*89c4ff92SAndroid Build Coastguard Worker typename std::enable_if_t<
100*89c4ff92SAndroid Build Coastguard Worker     std::is_unsigned<Dest>::value &&
101*89c4ff92SAndroid Build Coastguard Worker     std::is_signed<Source>::value
102*89c4ff92SAndroid Build Coastguard Worker     , Dest>
numeric_cast(Source sValue)103*89c4ff92SAndroid Build Coastguard Worker numeric_cast(Source sValue)
104*89c4ff92SAndroid Build Coastguard Worker {
105*89c4ff92SAndroid Build Coastguard Worker     static_assert(!std::is_floating_point<Source>::value && !std::is_floating_point<Dest>::value,
106*89c4ff92SAndroid Build Coastguard Worker         "numeric_cast doesn't cast floats.");
107*89c4ff92SAndroid Build Coastguard Worker 
108*89c4ff92SAndroid Build Coastguard Worker #if ENABLE_NUMERIC_CAST_CHECKS
109*89c4ff92SAndroid Build Coastguard Worker     if (sValue < 0)
110*89c4ff92SAndroid Build Coastguard Worker     {
111*89c4ff92SAndroid Build Coastguard Worker         ARM_PIPE_NUMERIC_CAST_CHECK(false, "numeric_cast failed casting negative value to unsigned type. "
112*89c4ff92SAndroid Build Coastguard Worker                                         "Underflow detected.");
113*89c4ff92SAndroid Build Coastguard Worker     }
114*89c4ff92SAndroid Build Coastguard Worker 
115*89c4ff92SAndroid Build Coastguard Worker     if (static_cast< typename std::make_unsigned<Source>::type >(sValue) > std::numeric_limits<Dest>::max())
116*89c4ff92SAndroid Build Coastguard Worker     {
117*89c4ff92SAndroid Build Coastguard Worker         ARM_PIPE_NUMERIC_CAST_CHECK(false, "numeric_cast failed casting signed type to unsigned type. "
118*89c4ff92SAndroid Build Coastguard Worker                                         "Overflow detected.");
119*89c4ff92SAndroid Build Coastguard Worker     }
120*89c4ff92SAndroid Build Coastguard Worker 
121*89c4ff92SAndroid Build Coastguard Worker #endif // ENABLE_NUMERIC_CAST_CHECKS
122*89c4ff92SAndroid Build Coastguard Worker     return static_cast<Dest>(sValue);
123*89c4ff92SAndroid Build Coastguard Worker }
124*89c4ff92SAndroid Build Coastguard Worker 
125*89c4ff92SAndroid Build Coastguard Worker #undef ENABLE_NUMERIC_CAST_CHECKS
126*89c4ff92SAndroid Build Coastguard Worker 
127*89c4ff92SAndroid Build Coastguard Worker } // namespace pipe
128*89c4ff92SAndroid Build Coastguard Worker } // namespace arm
129