Zserio C++17 runtime library 1.3.0
Built for Zserio 2.20.0
Loading...
Searching...
No Matches
ReflectableUtil.h
Go to the documentation of this file.
1#ifndef ZSERIO_REFLECTABLE_UTIL_H_INC
2#define ZSERIO_REFLECTABLE_UTIL_H_INC
3
4#include <algorithm>
5#include <cmath>
6#include <functional>
7#include <limits>
8#include <string_view>
9
11#include "zserio/Enums.h"
13#include "zserio/ITypeInfo.h"
14#include "zserio/Traits.h"
15#include "zserio/TypeInfoUtil.h"
16
17namespace zserio
18{
19
20namespace detail
21{
22
23template <typename T>
24struct gets_value_by_value
25 : std::integral_constant<bool,
26 std::is_arithmetic_v<T> || std::is_same_v<std::string_view, T> || std::is_enum_v<T> ||
27 is_bitmask_v<T> || is_numeric_wrapper_v<T>>
28{};
29
30} // namespace detail
31
36{
37public:
48 template <typename ALLOC = std::allocator<uint8_t>>
49 static bool equal(
51
63 template <typename T, typename ALLOC = std::allocator<uint8_t>,
64 typename std::enable_if<detail::gets_value_by_value<T>::value, int>::type = 0>
66 {
67 return reflectable->getAnyValue(allocator).template get<T>();
68 }
69
83 template <typename T, typename ALLOC = std::allocator<uint8_t>,
84 typename std::enable_if<!detail::gets_value_by_value<T>::value, int>::type = 0>
85 static const T& getValue(
87 {
88 return reflectable->getAnyValue(allocator).template get<std::reference_wrapper<const T>>().get();
89 }
90
104 template <typename T, typename ALLOC = std::allocator<uint8_t>,
105 typename std::enable_if<!detail::gets_value_by_value<T>::value &&
106 !std::is_same<BasicBitBuffer<ALLOC>, T>::value,
107 int>::type = 0>
109 {
110 return reflectable->getAnyValue(allocator).template get<std::reference_wrapper<T>>().get();
111 }
112
124 template <typename T, typename ALLOC = std::allocator<uint8_t>,
125 typename std::enable_if<std::is_same<BasicBitBuffer<ALLOC>, T>::value, int>::type = 0>
126 static const T& getValue(
128 {
129 return reflectable->getAnyValue(allocator).template get<std::reference_wrapper<const T>>().get();
130 }
131
141 template <typename T, typename ALLOC>
142 static T fromAny(const BasicAny<ALLOC>& any);
143
144private:
145 template <typename ALLOC>
146 static bool arraysEqual(const IBasicReflectableDataConstPtr<ALLOC>& lhsArray,
148
149 template <typename ALLOC>
150 static bool compoundsEqual(const IBasicReflectableDataConstPtr<ALLOC>& lhsCompound,
152
153 template <typename ALLOC>
154 static bool valuesEqual(const IBasicReflectableDataConstPtr<ALLOC>& lhsValue,
156
157 static bool doubleValuesAlmostEqual(double lhs, double rhs);
158};
159
160template <typename ALLOC>
163{
164 if (lhs == nullptr || rhs == nullptr)
165 {
166 return lhs == rhs;
167 }
168
169 const auto& lhsTypeInfo = lhs->getTypeInfo();
170 const auto& rhsTypeInfo = rhs->getTypeInfo();
171
172 if (lhsTypeInfo.getSchemaType() != rhsTypeInfo.getSchemaType() ||
173 lhsTypeInfo.getSchemaName() != rhsTypeInfo.getSchemaName())
174 {
175 return false;
176 }
177
178 if (lhs->isArray() || rhs->isArray())
179 {
180 if (!lhs->isArray() || !rhs->isArray())
181 {
182 return false;
183 }
184 return arraysEqual<ALLOC>(lhs, rhs);
185 }
186 else if (TypeInfoUtil::isCompound(lhsTypeInfo.getSchemaType()))
187 {
189 }
190 else
191 {
192 return valuesEqual<ALLOC>(lhs, rhs);
193 }
194}
195
196template <typename ALLOC>
197bool ReflectableUtil::arraysEqual(const IBasicReflectableDataConstPtr<ALLOC>& lhsArray,
199{
200 if (lhsArray->size() != rhsArray->size())
201 {
202 return false;
203 }
204
205 for (size_t i = 0; i < lhsArray->size(); ++i)
206 {
207 if (!equal<ALLOC>(lhsArray->at(i), rhsArray->at(i)))
208 {
209 return false;
210 }
211 }
212
213 return true;
214}
215
216template <typename ALLOC>
217bool ReflectableUtil::compoundsEqual(const IBasicReflectableDataConstPtr<ALLOC>& lhsCompound,
218 const IBasicReflectableDataConstPtr<ALLOC>& rhsCompound)
219{
220 if (TypeInfoUtil::hasChoice(lhsCompound->getTypeInfo().getSchemaType()))
221 {
222 if (lhsCompound->getChoice() != rhsCompound->getChoice())
223 {
224 return false;
225 }
226
227 if (!lhsCompound->getChoice().empty())
228 {
229 auto lhsField = lhsCompound->getField(lhsCompound->getChoice());
230 auto rhsField = rhsCompound->getField(rhsCompound->getChoice());
231 if (!equal<ALLOC>(lhsField, rhsField))
232 {
233 return false;
234 }
235 }
236 }
237 else
238 {
239 for (const auto& fieldInfo : lhsCompound->getTypeInfo().getFields())
240 {
241 auto lhsField = lhsCompound->getField(fieldInfo.schemaName);
242 auto rhsField = rhsCompound->getField(fieldInfo.schemaName);
243 if (!equal<ALLOC>(lhsField, rhsField))
244 {
245 return false;
246 }
247 }
248 }
249
250 return true;
251}
252
253template <typename ALLOC>
254bool ReflectableUtil::valuesEqual(const IBasicReflectableDataConstPtr<ALLOC>& lhsValue,
255 const IBasicReflectableDataConstPtr<ALLOC>& rhsValue)
256{
257 CppType cppType = lhsValue->getTypeInfo().getCppType();
258 if (cppType == CppType::ENUM || cppType == CppType::BITMASK)
259 {
260 cppType = lhsValue->getTypeInfo().getUnderlyingType().getCppType();
261 }
262
263 switch (cppType)
264 {
265 case CppType::BOOL:
266 return lhsValue->getBool() == rhsValue->getBool();
267 case CppType::INT8:
268 case CppType::INT16:
269 case CppType::INT32:
270 case CppType::INT64:
271 return lhsValue->toInt() == rhsValue->toInt();
272 case CppType::UINT8:
273 case CppType::UINT16:
274 case CppType::UINT32:
275 case CppType::UINT64:
276 return lhsValue->toUInt() == rhsValue->toUInt();
277 case CppType::FLOAT:
278 case CppType::DOUBLE:
279 return doubleValuesAlmostEqual(lhsValue->toDouble(), rhsValue->toDouble());
280 case CppType::BYTES:
281 {
282 Span<const uint8_t> lhs = lhsValue->getBytes();
283 Span<const uint8_t> rhs = rhsValue->getBytes();
284
285 return lhs.size() == rhs.size() && std::equal(lhs.begin(), lhs.end(), rhs.begin());
286 }
287 case CppType::STRING:
288 return lhsValue->getStringView() == rhsValue->getStringView();
290 return lhsValue->getBitBuffer() == rhsValue->getBitBuffer();
291 default:
292 throw CppRuntimeException("ReflectableUtil::valuesEqual - Unexpected C++ type!");
293 }
294}
295
296inline bool ReflectableUtil::doubleValuesAlmostEqual(double lhs, double rhs)
297{
298 if (std::isinf(lhs) || std::isinf(rhs))
299 {
300 return std::isinf(lhs) && std::isinf(rhs) && ((lhs > 0.0 && rhs > 0.0) || (lhs < 0.0 && rhs < 0.0));
301 }
302
303 if (std::isnan(lhs) || std::isnan(rhs))
304 {
305 return std::isnan(lhs) && std::isnan(rhs);
306 }
307
308 // see: https://en.cppreference.com/w/cpp/types/numeric_limits/epsilon
309 return std::fabs(lhs - rhs) <= std::numeric_limits<double>::epsilon() * std::fabs(lhs + rhs) ||
310 std::fabs(lhs - rhs) < std::numeric_limits<double>::min();
311}
312
313template <typename T, typename ALLOC>
315{
316 if constexpr (is_bitmask_v<T>)
317 {
318 using ZserioType = typename T::ZserioType;
319 using UnderlyingType = typename ZserioType::ValueType;
320
321 if (any.template isType<T>())
322 {
323 return any.template get<T>();
324 }
325 else if (any.template isType<ZserioType>())
326 {
327 return T(any.template get<ZserioType>());
328 }
329 else
330 {
331 return T(any.template get<UnderlyingType>());
332 }
333 }
334 else if constexpr (std::is_enum_v<T>)
335 {
336 using ZserioType = typename EnumTraits<T>::ZserioType;
337 using UnderlyingType = std::underlying_type_t<T>;
338
339 if (any.template isType<T>())
340 {
341 return any.template get<T>();
342 }
343 else if (any.template isType<ZserioType>())
344 {
345 return valueToEnum<T>(any.template get<ZserioType>());
346 }
347 else
348 {
349 return valueToEnum<T>(any.template get<UnderlyingType>());
350 }
351 }
352 else if constexpr (is_numeric_wrapper_v<T>)
353 {
354 if (any.template isType<T>())
355 {
356 return any.template get<T>();
357 }
358 else
359 {
360 return any.template get<typename T::ValueType>();
361 }
362 }
363 else
364 {
365 return any.template get<T>();
366 }
367}
368
369} // namespace zserio
370
371#endif // ZSERIO_REFLECTABLE_UTIL_H_INC
static T getValue(const IBasicReflectableDataConstPtr< ALLOC > &reflectable, const ALLOC &allocator=ALLOC())
static const T & getValue(const IBasicReflectableDataConstPtr< ALLOC > &reflectable, const ALLOC &allocator=ALLOC())
static bool equal(const IBasicReflectableDataConstPtr< ALLOC > &lhs, const IBasicReflectableDataConstPtr< ALLOC > &rhs)
static const T & getValue(const IBasicReflectableDataPtr< ALLOC > &reflectable, const ALLOC &allocator=ALLOC())
static T fromAny(const BasicAny< ALLOC > &any)
static T & getValue(const IBasicReflectableDataPtr< ALLOC > &reflectable, const ALLOC &allocator=ALLOC())
decltype(auto) get(BasicVariant< ALLOC, INDEX, T... > &var)
Definition Variant.h:511
IBasicReflectableDataConstPtr< ALLOC > reflectable(const T &value, const ALLOC &allocator=ALLOC())
static bool hasChoice(SchemaType schemaType)
static bool isCompound(SchemaType schemaType)