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