Zserio C++ runtime library  1.1.0
Built for Zserio 2.15.0
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 
10 #include "zserio/IReflectable.h"
11 #include "zserio/ITypeInfo.h"
12 #include "zserio/StringView.h"
13 #include "zserio/Traits.h"
14 #include "zserio/TypeInfoUtil.h"
15 
16 namespace zserio
17 {
18 
19 namespace detail
20 {
21 
22 template <typename T>
23 struct gets_value_by_value
24  : std::integral_constant<bool,
25  std::is_arithmetic<T>::value || std::is_same<StringView, T>::value ||
26  std::is_enum<T>::value || is_bitmask<T>::value>
27 {};
28 
29 } // namespace detail
30 
35 {
36 public:
47  template <typename ALLOC = std::allocator<uint8_t>>
49 
61  template <typename T, typename ALLOC = std::allocator<uint8_t>,
62  typename std::enable_if<detail::gets_value_by_value<T>::value, int>::type = 0>
63  static T getValue(const IBasicReflectableConstPtr<ALLOC>& reflectable, const ALLOC& allocator = ALLOC())
64  {
65  return reflectable->getAnyValue(allocator).template get<T>();
66  }
67 
81  template <typename T, typename ALLOC = std::allocator<uint8_t>,
82  typename std::enable_if<!detail::gets_value_by_value<T>::value, int>::type = 0>
83  static const T& getValue(
84  const IBasicReflectableConstPtr<ALLOC>& reflectable, const ALLOC& allocator = ALLOC())
85  {
86  return reflectable->getAnyValue(allocator).template get<std::reference_wrapper<const T>>().get();
87  }
88 
102  template <typename T, typename ALLOC = std::allocator<uint8_t>,
103  typename std::enable_if<!detail::gets_value_by_value<T>::value &&
104  !std::is_same<BasicBitBuffer<ALLOC>, T>::value,
105  int>::type = 0>
106  static T& getValue(const IBasicReflectablePtr<ALLOC>& reflectable, const ALLOC& allocator = ALLOC())
107  {
108  return reflectable->getAnyValue(allocator).template get<std::reference_wrapper<T>>().get();
109  }
110 
122  template <typename T, typename ALLOC = std::allocator<uint8_t>,
123  typename std::enable_if<std::is_same<BasicBitBuffer<ALLOC>, T>::value, int>::type = 0>
124  static const T& getValue(const IBasicReflectablePtr<ALLOC>& reflectable, const ALLOC& allocator = ALLOC())
125  {
126  return reflectable->getAnyValue(allocator).template get<std::reference_wrapper<const T>>().get();
127  }
128 
129 private:
130  template <typename ALLOC>
131  static bool arraysEqual(
132  const IBasicReflectableConstPtr<ALLOC>& lhsArray, const IBasicReflectableConstPtr<ALLOC>& rhsArray);
133 
134  template <typename ALLOC>
135  static bool compoundsEqual(const IBasicReflectableConstPtr<ALLOC>& lhsCompound,
136  const IBasicReflectableConstPtr<ALLOC>& rhsCompound);
137 
138  template <typename ALLOC>
139  static bool valuesEqual(
140  const IBasicReflectableConstPtr<ALLOC>& lhsValue, const IBasicReflectableConstPtr<ALLOC>& rhsValue);
141 
142  static bool doubleValuesAlmostEqual(double lhs, double rhs);
143 };
144 
145 template <typename ALLOC>
148 {
149  if (lhs == nullptr || rhs == nullptr)
150  {
151  return lhs == rhs;
152  }
153 
154  const auto& lhsTypeInfo = lhs->getTypeInfo();
155  const auto& rhsTypeInfo = rhs->getTypeInfo();
156 
157  if (lhsTypeInfo.getSchemaType() != rhsTypeInfo.getSchemaType() ||
158  lhsTypeInfo.getSchemaName() != rhsTypeInfo.getSchemaName())
159  {
160  return false;
161  }
162 
163  if (lhs->isArray() || rhs->isArray())
164  {
165  if (!lhs->isArray() || !rhs->isArray())
166  {
167  return false;
168  }
169  return arraysEqual<ALLOC>(lhs, rhs);
170  }
171  else if (TypeInfoUtil::isCompound(lhsTypeInfo.getSchemaType()))
172  {
173  return compoundsEqual<ALLOC>(lhs, rhs);
174  }
175  else
176  {
177  return valuesEqual<ALLOC>(lhs, rhs);
178  }
179 }
180 
181 template <typename ALLOC>
182 bool ReflectableUtil::arraysEqual(
184 {
185  if (lhsArray->size() != rhsArray->size())
186  {
187  return false;
188  }
189 
190  for (size_t i = 0; i < lhsArray->size(); ++i)
191  {
192  if (!equal<ALLOC>(lhsArray->at(i), rhsArray->at(i)))
193  {
194  return false;
195  }
196  }
197 
198  return true;
199 }
200 
201 template <typename ALLOC>
202 bool ReflectableUtil::compoundsEqual(const IBasicReflectableConstPtr<ALLOC>& lhsCompound,
203  const IBasicReflectableConstPtr<ALLOC>& rhsCompound)
204 {
205  for (const auto& parameterInfo : lhsCompound->getTypeInfo().getParameters())
206  {
207  auto lhsParameter = lhsCompound->getParameter(parameterInfo.schemaName);
208  auto rhsParameter = rhsCompound->getParameter(parameterInfo.schemaName);
209  if (!equal<ALLOC>(lhsParameter, rhsParameter))
210  {
211  return false;
212  }
213  }
214 
215  if (TypeInfoUtil::hasChoice(lhsCompound->getTypeInfo().getSchemaType()))
216  {
217  if (lhsCompound->getChoice() != rhsCompound->getChoice())
218  {
219  return false;
220  }
221 
222  if (!lhsCompound->getChoice().empty())
223  {
224  auto lhsField = lhsCompound->getField(lhsCompound->getChoice());
225  auto rhsField = rhsCompound->getField(rhsCompound->getChoice());
226  if (!equal<ALLOC>(lhsField, rhsField))
227  {
228  return false;
229  }
230  }
231  }
232  else
233  {
234  for (const auto& fieldInfo : lhsCompound->getTypeInfo().getFields())
235  {
236  auto lhsField = lhsCompound->getField(fieldInfo.schemaName);
237  auto rhsField = rhsCompound->getField(fieldInfo.schemaName);
238  if (!equal<ALLOC>(lhsField, rhsField))
239  {
240  return false;
241  }
242  }
243  }
244 
245  return true;
246 }
247 
248 template <typename ALLOC>
249 bool ReflectableUtil::valuesEqual(
250  const IBasicReflectableConstPtr<ALLOC>& lhsValue, const IBasicReflectableConstPtr<ALLOC>& rhsValue)
251 {
252  CppType cppType = lhsValue->getTypeInfo().getCppType();
253  if (cppType == CppType::ENUM || cppType == CppType::BITMASK)
254  {
255  cppType = lhsValue->getTypeInfo().getUnderlyingType().getCppType();
256  }
257 
258  switch (cppType)
259  {
260  case CppType::BOOL:
261  return lhsValue->getBool() == rhsValue->getBool();
262  case CppType::INT8:
263  case CppType::INT16:
264  case CppType::INT32:
265  case CppType::INT64:
266  return lhsValue->toInt() == rhsValue->toInt();
267  case CppType::UINT8:
268  case CppType::UINT16:
269  case CppType::UINT32:
270  case CppType::UINT64:
271  return lhsValue->toUInt() == rhsValue->toUInt();
272  case CppType::FLOAT:
273  case CppType::DOUBLE:
274  return doubleValuesAlmostEqual(lhsValue->toDouble(), rhsValue->toDouble());
275  case CppType::BYTES:
276  {
277  Span<const uint8_t> lhs = lhsValue->getBytes();
278  Span<const uint8_t> rhs = rhsValue->getBytes();
279 
280  return lhs.size() == rhs.size() && std::equal(lhs.begin(), lhs.end(), rhs.begin());
281  }
282  case CppType::STRING:
283  return lhsValue->getStringView() == rhsValue->getStringView();
284  case CppType::BIT_BUFFER:
285  return lhsValue->getBitBuffer() == rhsValue->getBitBuffer();
286  default:
287  throw CppRuntimeException("ReflectableUtil::valuesEqual - Unexpected C++ type!");
288  }
289 }
290 
291 inline bool ReflectableUtil::doubleValuesAlmostEqual(double lhs, double rhs)
292 {
293  if (std::isinf(lhs) || std::isinf(rhs))
294  {
295  return std::isinf(lhs) && std::isinf(rhs) && ((lhs > 0.0 && rhs > 0.0) || (lhs < 0.0 && rhs < 0.0));
296  }
297 
298  if (std::isnan(lhs) || std::isnan(rhs))
299  {
300  return std::isnan(lhs) && std::isnan(rhs);
301  }
302 
303  // see: https://en.cppreference.com/w/cpp/types/numeric_limits/epsilon
304  return std::fabs(lhs - rhs) <= std::numeric_limits<double>::epsilon() * std::fabs(lhs + rhs) ||
305  std::fabs(lhs - rhs) < std::numeric_limits<double>::min();
306 }
307 
308 } // namespace zserio
309 
310 #endif // ZSERIO_REFLECTABLE_UTIL_H_INC
static bool equal(const IBasicReflectableConstPtr< ALLOC > &lhs, const IBasicReflectableConstPtr< ALLOC > &rhs)
static T getValue(const IBasicReflectableConstPtr< ALLOC > &reflectable, const ALLOC &allocator=ALLOC())
static const T & getValue(const IBasicReflectablePtr< ALLOC > &reflectable, const ALLOC &allocator=ALLOC())
static const T & getValue(const IBasicReflectableConstPtr< ALLOC > &reflectable, const ALLOC &allocator=ALLOC())
static T & getValue(const IBasicReflectablePtr< ALLOC > &reflectable, const ALLOC &allocator=ALLOC())
typename IBasicReflectable< ALLOC >::Ptr IBasicReflectablePtr
Definition: IReflectable.h:531
typename IBasicReflectable< ALLOC >::ConstPtr IBasicReflectableConstPtr
Definition: IReflectable.h:534
static bool hasChoice(SchemaType schemaType)
static bool isCompound(SchemaType schemaType)
Definition: TypeInfoUtil.cpp:6