Line data Source code
1 : /********************************************************************************
2 : * Copyright (c) 2026 Accenture
3 : *
4 : * This program and the accompanying materials are made available under the
5 : * terms of the Apache License Version 2.0 which is available at
6 : * https://www.apache.org/licenses/LICENSE-2.0
7 : *
8 : * SPDX-License-Identifier: Apache-2.0
9 : ********************************************************************************/
10 :
11 : #pragma once
12 :
13 : #include "someip/StringEncoding.h"
14 :
15 : #include <etl/type_list.h>
16 : #include <util/meta/Bitmask.h>
17 :
18 : #include <cmath>
19 : #include <cstdint>
20 : #include <cstring>
21 : #include <limits>
22 :
23 : namespace someip
24 : {
25 : /** List of SOME/IP base types */
26 : using BaseTypes = ::etl::type_list<
27 : char,
28 : uint8_t,
29 : uint16_t,
30 : uint32_t,
31 : uint64_t,
32 : int8_t,
33 : int16_t,
34 : int32_t,
35 : int64_t,
36 : bool,
37 : float_t,
38 : double_t>;
39 :
40 : } // namespace someip
41 :
42 : namespace someip
43 : {
44 : namespace internal
45 : {
46 : /// \cond internal
47 : enum
48 : {
49 : IEC559_NOT_SUPPORTED = false,
50 : IEC559_SUPPORTED = true
51 : };
52 :
53 : template<typename RT, typename T>
54 90 : static RT conversion(T const value)
55 : {
56 : static_assert(
57 : sizeof(T) == sizeof(RT),
58 : "floating point to/from integral conversion type not the same size");
59 :
60 : // in C it is possible to use unions to convert from one type to another (type-punning)
61 : // in C++ this behavior is compiler dependent and can therefore be undefined behavior
62 : // as a solution memcpy can be used to convert from one type into another type
63 90 : RT dest{};
64 90 : std::memcpy(&dest, &value, sizeof(value));
65 90 : return dest;
66 : }
67 :
68 : template<typename T>
69 : struct IEEE756Traits;
70 :
71 : template<>
72 : struct IEEE756Traits<float_t>
73 : {
74 : enum
75 : {
76 : MAX_EXP = 256
77 : };
78 :
79 : static uint32_t const IEEE756_ZERO = 0x00000000U;
80 : static uint32_t const IEEE756_NEGATIVE_ZERO = 0x80000000U;
81 : static uint32_t const IEEE756_INFINITY = 0x7F800000U;
82 : static uint32_t const IEEE756_NEGATIVE_INFINITY = 0xFF800000U;
83 : static uint32_t const IEEE756_NAN = 0x7FFFFFFFU;
84 : };
85 :
86 : template<>
87 : struct IEEE756Traits<double_t>
88 : {
89 : enum
90 : {
91 : MAX_EXP = 2048
92 : };
93 :
94 : static uint64_t const IEEE756_ZERO = 0x0000000000000000U;
95 : static uint64_t const IEEE756_NEGATIVE_ZERO = 0x8000000000000000U;
96 : static uint64_t const IEEE756_INFINITY = 0x7FF0000000000000U;
97 : static uint64_t const IEEE756_NEGATIVE_INFINITY = 0xFFF0000000000000U;
98 : static uint64_t const IEEE756_NAN = 0x7FFFFFFFFFFFFFFFU;
99 : };
100 :
101 : template<bool IS_IEC599>
102 : struct PackIEEE754Dispatcher;
103 :
104 : template<>
105 : struct PackIEEE754Dispatcher<IEC559_SUPPORTED>
106 : {
107 : template<typename RT, typename T, uint32_t EXP_BITS>
108 51 : static RT packIEEE754(T const value)
109 : {
110 51 : return conversion<RT, T>(value);
111 : }
112 : };
113 :
114 : template<>
115 : struct PackIEEE754Dispatcher<IEC559_NOT_SUPPORTED>
116 : {
117 : template<typename RT, typename T, uint32_t EXP_BITS>
118 16 : static RT packIEEE754(T const value)
119 : {
120 16 : uint32_t const BITS = (static_cast<uint32_t>(sizeof(T)) * 8U);
121 16 : uint32_t const FRACTION_BITS = BITS - EXP_BITS - 1U;
122 16 : if (value == static_cast<T>(0.0))
123 : {
124 4 : if (conversion<RT, T>(value) == static_cast<RT>(0.0))
125 : {
126 2 : return IEEE756Traits<T>::IEEE756_ZERO;
127 : }
128 :
129 2 : return IEEE756Traits<T>::IEEE756_NEGATIVE_ZERO;
130 : }
131 12 : if (value == std::numeric_limits<T>::infinity())
132 : {
133 2 : return IEEE756Traits<T>::IEEE756_INFINITY;
134 : }
135 10 : if (value == -std::numeric_limits<T>::infinity())
136 : {
137 2 : return IEEE756Traits<T>::IEEE756_NEGATIVE_INFINITY;
138 : }
139 8 : if (value != value)
140 : {
141 0 : return IEEE756Traits<T>::IEEE756_NAN;
142 : }
143 :
144 8 : T valueNormalized = value;
145 8 : RT sign = 0U;
146 8 : if (value < static_cast<T>(0))
147 : {
148 4 : sign = 1U;
149 4 : valueNormalized = -valueNormalized;
150 : }
151 8 : int32_t shift = 0;
152 20 : while ((valueNormalized >= static_cast<T>(2.0)) && (shift < IEEE756Traits<T>::MAX_EXP))
153 : {
154 12 : valueNormalized /= static_cast<T>(2.0);
155 12 : ++shift;
156 : }
157 8 : int32_t rounds = 0;
158 8 : while ((valueNormalized < 1.0) && (rounds < IEEE756Traits<T>::MAX_EXP))
159 : {
160 0 : valueNormalized *= static_cast<T>(2.0);
161 0 : --shift;
162 0 : ++rounds;
163 : }
164 8 : valueNormalized = valueNormalized - static_cast<T>(1.0);
165 8 : RT const fraction
166 8 : = valueNormalized * ((static_cast<RT>(1) << FRACTION_BITS) + static_cast<T>(0.5));
167 8 : RT const exponent
168 8 : = shift + static_cast<int32_t>(((static_cast<uint32_t>(1U) << (EXP_BITS - 1U)) - 1U));
169 :
170 8 : return (sign << (BITS - 1U)) | (exponent << FRACTION_BITS) | fraction;
171 : }
172 : };
173 :
174 : template<bool IS_IEC599>
175 : struct UnpackIEEE754Dispatcher;
176 :
177 : template<>
178 : struct UnpackIEEE754Dispatcher<IEC559_SUPPORTED>
179 : {
180 : template<typename RT, typename T, uint32_t EXP_BITS>
181 35 : static RT unpackIEEE754(T const value)
182 : {
183 35 : return conversion<RT, T>(value);
184 : }
185 : };
186 :
187 : template<>
188 : struct UnpackIEEE754Dispatcher<IEC559_NOT_SUPPORTED>
189 : {
190 : template<typename RT, typename T, uint32_t EXP_BITS>
191 18 : static RT unpackIEEE754(T const value)
192 : {
193 18 : uint32_t const BITS = static_cast<uint32_t>(sizeof(T) * 8U);
194 18 : uint32_t const FRACTION_BITS = BITS - EXP_BITS - 1U;
195 18 : if (value == IEEE756Traits<RT>::IEEE756_ZERO)
196 : {
197 2 : return static_cast<RT>(0.0);
198 : }
199 16 : if (value == IEEE756Traits<RT>::IEEE756_NEGATIVE_ZERO)
200 : {
201 2 : return -static_cast<RT>(0.0);
202 : }
203 14 : if (value == IEEE756Traits<RT>::IEEE756_INFINITY)
204 : {
205 2 : return std::numeric_limits<RT>::infinity();
206 : }
207 12 : if (value == IEEE756Traits<RT>::IEEE756_NEGATIVE_INFINITY)
208 : {
209 2 : return -std::numeric_limits<RT>::infinity();
210 : }
211 10 : T const sign = (value >> (BITS - 1U));
212 10 : T const exponent
213 : = (value & static_cast<T>(::util::meta::Bitmask<uint64_t, BITS - 1U>::value))
214 10 : >> FRACTION_BITS;
215 10 : T const fraction
216 : = (value & static_cast<T>(::util::meta::Bitmask<uint64_t, FRACTION_BITS>::value));
217 :
218 10 : if ((::util::meta::Bitmask<uint64_t, EXP_BITS>::value == exponent) && (fraction > 0U))
219 : {
220 2 : return std::numeric_limits<RT>::quiet_NaN();
221 : }
222 8 : RT valueNormalized = static_cast<RT>(fraction);
223 8 : int32_t shift = static_cast<int32_t>(
224 8 : exponent - static_cast<T>(::util::meta::Bitmask<uint64_t, EXP_BITS - 1U>::value));
225 :
226 : valueNormalized
227 8 : /= static_cast<T>(static_cast<T>(1U) << FRACTION_BITS) + static_cast<RT>(0.5);
228 8 : valueNormalized += static_cast<RT>(1.0);
229 :
230 8 : while (shift < 0)
231 : {
232 0 : valueNormalized /= static_cast<RT>(2.0);
233 0 : ++shift;
234 : }
235 20 : while (shift > 0)
236 : {
237 12 : valueNormalized *= static_cast<RT>(2.0);
238 12 : --shift;
239 : }
240 8 : if (sign != 0U)
241 : {
242 4 : valueNormalized = -valueNormalized;
243 : }
244 8 : return valueNormalized;
245 : }
246 : };
247 :
248 : template<typename RT, typename T, uint32_t EXP_BITS>
249 17 : RT packIEEE754(T const value)
250 : {
251 : return PackIEEE754Dispatcher<
252 17 : std::numeric_limits<T>::is_iec559>::template packIEEE754<RT, T, EXP_BITS>(value);
253 : }
254 :
255 : template<typename RT, typename T, uint32_t EXP_BITS>
256 17 : RT unpackIEEE754(T const value)
257 : {
258 : return UnpackIEEE754Dispatcher<
259 17 : std::numeric_limits<RT>::is_iec559>::template unpackIEEE754<RT, T, EXP_BITS>(value);
260 : }
261 :
262 : template<typename T, bool IS_BASIC_TYPE>
263 : struct GetSizeDispatcher;
264 :
265 : template<typename T>
266 : struct GetSizeDispatcher<T, true>
267 : {
268 90 : static uint32_t getSize(T const& /* t */) { return static_cast<uint32_t>(sizeof(T)); }
269 : };
270 :
271 : template<typename T>
272 : struct GetSizeDispatcher<T, false>
273 : {
274 : static uint32_t getSize(T const& t) { return t.getSize(); }
275 : };
276 :
277 : template<typename T>
278 : struct GetSizeHelper
279 : {
280 81 : static uint32_t getSize(T const& t, uint32_t const /* lengthSize */)
281 : {
282 81 : return GetSizeDispatcher<T, ::etl::type_list_contains<BaseTypes, T>::value>::getSize(t);
283 : }
284 :
285 : static uint32_t
286 9 : getSize(T const& t, uint32_t const /* lengthSize */, Encoding const /* encoding */)
287 : {
288 9 : return GetSizeDispatcher<T, ::etl::type_list_contains<BaseTypes, T>::value>::getSize(t);
289 : }
290 : };
291 :
292 : /// \endcond
293 : } // namespace internal
294 : } // namespace someip
|