Zserio C++ runtime library  1.0.0
Built for Zserio 2.13.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 <functional>
6 #include <cmath>
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 : std::integral_constant<bool,
24  std::is_arithmetic<T>::value ||
25  std::is_same<StringView, T>::value ||
26  std::is_enum<T>::value ||
27  is_bitmask<T>::value>
28 {};
29 
30 } // namespace detail
31 
36 {
37 public:
48  template <typename ALLOC = std::allocator<uint8_t>>
49  static bool equal(const IBasicReflectableConstPtr<ALLOC>& lhs,
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>
65  static T getValue(const IBasicReflectableConstPtr<ALLOC>& reflectable, const ALLOC& allocator = ALLOC())
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(const IBasicReflectableConstPtr<ALLOC>& reflectable,
86  const ALLOC& allocator = ALLOC())
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<
106  !detail::gets_value_by_value<T>::value &&
107  !std::is_same<BasicBitBuffer<ALLOC>, T>::value, int>::type = 0>
108  static T& getValue(const IBasicReflectablePtr<ALLOC>& reflectable, const ALLOC& allocator = ALLOC())
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(const IBasicReflectablePtr<ALLOC>& reflectable, const ALLOC& allocator = ALLOC())
127  {
128  return reflectable->getAnyValue(allocator).template get<std::reference_wrapper<const T>>().get();
129  }
130 
131 private:
132  template <typename ALLOC>
133  static bool arraysEqual(const IBasicReflectableConstPtr<ALLOC>& lhsArray,
134  const IBasicReflectableConstPtr<ALLOC>& rhsArray);
135 
136  template <typename ALLOC>
137  static bool compoundsEqual(const IBasicReflectableConstPtr<ALLOC>& lhsCompound,
138  const IBasicReflectableConstPtr<ALLOC>& rhsCompound);
139 
140  template <typename ALLOC>
141  static bool valuesEqual(const IBasicReflectableConstPtr<ALLOC>& lhsValue,
142  const IBasicReflectableConstPtr<ALLOC>& rhsValue);
143 
144  static bool doubleValuesAlmostEqual(double lhs, double rhs);
145 };
146 
147 template <typename ALLOC>
150 {
151  if (lhs == nullptr || rhs == nullptr)
152  return lhs == rhs;
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  return false;
160 
161  if (lhs->isArray() || rhs->isArray())
162  {
163  if (!lhs->isArray() || !rhs->isArray())
164  return false;
165  return arraysEqual<ALLOC>(lhs, rhs);
166  }
167  else if (TypeInfoUtil::isCompound(lhsTypeInfo.getSchemaType()))
168  {
169  return compoundsEqual<ALLOC>(lhs, rhs);
170  }
171  else
172  {
173  return valuesEqual<ALLOC>(lhs, rhs);
174  }
175 }
176 
177 template <typename ALLOC>
178 bool ReflectableUtil::arraysEqual(const IBasicReflectableConstPtr<ALLOC>& lhsArray,
179  const IBasicReflectableConstPtr<ALLOC>& rhsArray)
180 {
181  if (lhsArray->size() != rhsArray->size())
182  return false;
183 
184  for (size_t i = 0; i < lhsArray->size(); ++i)
185  {
186  if (!equal<ALLOC>(lhsArray->at(i), rhsArray->at(i)))
187  return false;
188  }
189 
190  return true;
191 }
192 
193 template <typename ALLOC>
194 bool ReflectableUtil::compoundsEqual(const IBasicReflectableConstPtr<ALLOC>& lhsCompound,
195  const IBasicReflectableConstPtr<ALLOC>& rhsCompound)
196 {
197  for (const auto& parameterInfo : lhsCompound->getTypeInfo().getParameters())
198  {
199  auto lhsParameter = lhsCompound->getParameter(parameterInfo.schemaName);
200  auto rhsParameter = rhsCompound->getParameter(parameterInfo.schemaName);
201  if (!equal<ALLOC>(lhsParameter, rhsParameter))
202  return false;
203  }
204 
205  if (TypeInfoUtil::hasChoice(lhsCompound->getTypeInfo().getSchemaType()))
206  {
207  if (lhsCompound->getChoice() != rhsCompound->getChoice())
208  return false;
209 
210  if (!lhsCompound->getChoice().empty())
211  {
212  auto lhsField = lhsCompound->getField(lhsCompound->getChoice());
213  auto rhsField = rhsCompound->getField(rhsCompound->getChoice());
214  if (!equal<ALLOC>(lhsField, rhsField))
215  return false;
216  }
217  }
218  else
219  {
220  for (const auto& fieldInfo : lhsCompound->getTypeInfo().getFields())
221  {
222  auto lhsField = lhsCompound->getField(fieldInfo.schemaName);
223  auto rhsField = rhsCompound->getField(fieldInfo.schemaName);
224  if (!equal<ALLOC>(lhsField, rhsField))
225  return false;
226  }
227  }
228 
229  return true;
230 }
231 
232 template <typename ALLOC>
233 bool ReflectableUtil::valuesEqual(const IBasicReflectableConstPtr<ALLOC>& lhsValue,
234  const IBasicReflectableConstPtr<ALLOC>& rhsValue)
235 {
236  CppType cppType = lhsValue->getTypeInfo().getCppType();
237  if (cppType == CppType::ENUM || cppType == CppType::BITMASK)
238  cppType = lhsValue->getTypeInfo().getUnderlyingType().getCppType();
239 
240  switch (cppType)
241  {
242  case CppType::BOOL:
243  return lhsValue->getBool() == rhsValue->getBool();
244  case CppType::INT8:
245  case CppType::INT16:
246  case CppType::INT32:
247  case CppType::INT64:
248  return lhsValue->toInt() == rhsValue->toInt();
249  case CppType::UINT8:
250  case CppType::UINT16:
251  case CppType::UINT32:
252  case CppType::UINT64:
253  return lhsValue->toUInt() == rhsValue->toUInt();
254  case CppType::FLOAT:
255  case CppType::DOUBLE:
256  return doubleValuesAlmostEqual(lhsValue->toDouble(), rhsValue->toDouble());
257  case CppType::BYTES:
258  {
259  Span<const uint8_t> lhs = lhsValue->getBytes();
260  Span<const uint8_t> rhs = rhsValue->getBytes();
261 
262  return lhs.size() == rhs.size() && std::equal(lhs.begin(), lhs.end(), rhs.begin());
263  }
264  case CppType::STRING:
265  return lhsValue->getStringView() == rhsValue->getStringView();
266  case CppType::BIT_BUFFER:
267  return lhsValue->getBitBuffer() == rhsValue->getBitBuffer();
268  default:
269  throw CppRuntimeException("ReflectableUtil::valuesEqual - Unexpected C++ type!");
270  }
271 }
272 
273 inline bool ReflectableUtil::doubleValuesAlmostEqual(double lhs, double rhs)
274 {
275  if (std::isinf(lhs) || std::isinf(rhs))
276  return std::isinf(lhs) && std::isinf(rhs) && ((lhs > 0.0 && rhs > 0.0) || (lhs < 0.0 && rhs < 0.0));
277 
278  if (std::isnan(lhs) || std::isnan(rhs))
279  return std::isnan(lhs) && std::isnan(rhs);
280 
281  // see: https://en.cppreference.com/w/cpp/types/numeric_limits/epsilon
282  return std::fabs(lhs - rhs) <= std::numeric_limits<double>::epsilon() * std::fabs(lhs + rhs)
283  || std::fabs(lhs - rhs) < std::numeric_limits<double>::min();
284 }
285 
286 } // namespace zserio
287 
288 #endif // ZSERIO_REFLECTABLE_UTIL_H_INC
typename IBasicReflectable< ALLOC >::ConstPtr IBasicReflectableConstPtr
Definition: IReflectable.h:519
typename IBasicReflectable< ALLOC >::Ptr IBasicReflectablePtr
Definition: IReflectable.h:516
static T getValue(const IBasicReflectableConstPtr< ALLOC > &reflectable, const ALLOC &allocator=ALLOC())
static const T & getValue(const IBasicReflectablePtr< ALLOC > &reflectable, const ALLOC &allocator=ALLOC())
constexpr size_type size() const noexcept
Definition: Span.h:276
static bool isCompound(SchemaType schemaType)
Definition: TypeInfoUtil.cpp:6
static const T & getValue(const IBasicReflectableConstPtr< ALLOC > &reflectable, const ALLOC &allocator=ALLOC())
static bool hasChoice(SchemaType schemaType)
static bool equal(const IBasicReflectableConstPtr< ALLOC > &lhs, const IBasicReflectableConstPtr< ALLOC > &rhs)
constexpr iterator begin() const noexcept
Definition: Span.h:195
constexpr iterator end() const noexcept
Definition: Span.h:205
static T & getValue(const IBasicReflectablePtr< ALLOC > &reflectable, const ALLOC &allocator=ALLOC())