Zserio C++ runtime library  1.0.1
Built for Zserio 2.14.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  return lhs == rhs;
151 
152  const auto& lhsTypeInfo = lhs->getTypeInfo();
153  const auto& rhsTypeInfo = rhs->getTypeInfo();
154 
155  if (lhsTypeInfo.getSchemaType() != rhsTypeInfo.getSchemaType() ||
156  lhsTypeInfo.getSchemaName() != rhsTypeInfo.getSchemaName())
157  return false;
158 
159  if (lhs->isArray() || rhs->isArray())
160  {
161  if (!lhs->isArray() || !rhs->isArray())
162  return false;
163  return arraysEqual<ALLOC>(lhs, rhs);
164  }
165  else if (TypeInfoUtil::isCompound(lhsTypeInfo.getSchemaType()))
166  {
167  return compoundsEqual<ALLOC>(lhs, rhs);
168  }
169  else
170  {
171  return valuesEqual<ALLOC>(lhs, rhs);
172  }
173 }
174 
175 template <typename ALLOC>
176 bool ReflectableUtil::arraysEqual(
178 {
179  if (lhsArray->size() != rhsArray->size())
180  return false;
181 
182  for (size_t i = 0; i < lhsArray->size(); ++i)
183  {
184  if (!equal<ALLOC>(lhsArray->at(i), rhsArray->at(i)))
185  return false;
186  }
187 
188  return true;
189 }
190 
191 template <typename ALLOC>
192 bool ReflectableUtil::compoundsEqual(const IBasicReflectableConstPtr<ALLOC>& lhsCompound,
193  const IBasicReflectableConstPtr<ALLOC>& rhsCompound)
194 {
195  for (const auto& parameterInfo : lhsCompound->getTypeInfo().getParameters())
196  {
197  auto lhsParameter = lhsCompound->getParameter(parameterInfo.schemaName);
198  auto rhsParameter = rhsCompound->getParameter(parameterInfo.schemaName);
199  if (!equal<ALLOC>(lhsParameter, rhsParameter))
200  return false;
201  }
202 
203  if (TypeInfoUtil::hasChoice(lhsCompound->getTypeInfo().getSchemaType()))
204  {
205  if (lhsCompound->getChoice() != rhsCompound->getChoice())
206  return false;
207 
208  if (!lhsCompound->getChoice().empty())
209  {
210  auto lhsField = lhsCompound->getField(lhsCompound->getChoice());
211  auto rhsField = rhsCompound->getField(rhsCompound->getChoice());
212  if (!equal<ALLOC>(lhsField, rhsField))
213  return false;
214  }
215  }
216  else
217  {
218  for (const auto& fieldInfo : lhsCompound->getTypeInfo().getFields())
219  {
220  auto lhsField = lhsCompound->getField(fieldInfo.schemaName);
221  auto rhsField = rhsCompound->getField(fieldInfo.schemaName);
222  if (!equal<ALLOC>(lhsField, rhsField))
223  return false;
224  }
225  }
226 
227  return true;
228 }
229 
230 template <typename ALLOC>
231 bool ReflectableUtil::valuesEqual(
232  const IBasicReflectableConstPtr<ALLOC>& lhsValue, const IBasicReflectableConstPtr<ALLOC>& rhsValue)
233 {
234  CppType cppType = lhsValue->getTypeInfo().getCppType();
235  if (cppType == CppType::ENUM || cppType == CppType::BITMASK)
236  cppType = lhsValue->getTypeInfo().getUnderlyingType().getCppType();
237 
238  switch (cppType)
239  {
240  case CppType::BOOL:
241  return lhsValue->getBool() == rhsValue->getBool();
242  case CppType::INT8:
243  case CppType::INT16:
244  case CppType::INT32:
245  case CppType::INT64:
246  return lhsValue->toInt() == rhsValue->toInt();
247  case CppType::UINT8:
248  case CppType::UINT16:
249  case CppType::UINT32:
250  case CppType::UINT64:
251  return lhsValue->toUInt() == rhsValue->toUInt();
252  case CppType::FLOAT:
253  case CppType::DOUBLE:
254  return doubleValuesAlmostEqual(lhsValue->toDouble(), rhsValue->toDouble());
255  case CppType::BYTES:
256  {
257  Span<const uint8_t> lhs = lhsValue->getBytes();
258  Span<const uint8_t> rhs = rhsValue->getBytes();
259 
260  return lhs.size() == rhs.size() && std::equal(lhs.begin(), lhs.end(), rhs.begin());
261  }
262  case CppType::STRING:
263  return lhsValue->getStringView() == rhsValue->getStringView();
264  case CppType::BIT_BUFFER:
265  return lhsValue->getBitBuffer() == rhsValue->getBitBuffer();
266  default:
267  throw CppRuntimeException("ReflectableUtil::valuesEqual - Unexpected C++ type!");
268  }
269 }
270 
271 inline bool ReflectableUtil::doubleValuesAlmostEqual(double lhs, double rhs)
272 {
273  if (std::isinf(lhs) || std::isinf(rhs))
274  return std::isinf(lhs) && std::isinf(rhs) && ((lhs > 0.0 && rhs > 0.0) || (lhs < 0.0 && rhs < 0.0));
275 
276  if (std::isnan(lhs) || std::isnan(rhs))
277  return std::isnan(lhs) && std::isnan(rhs);
278 
279  // see: https://en.cppreference.com/w/cpp/types/numeric_limits/epsilon
280  return std::fabs(lhs - rhs) <= std::numeric_limits<double>::epsilon() * std::fabs(lhs + rhs) ||
281  std::fabs(lhs - rhs) < std::numeric_limits<double>::min();
282 }
283 
284 } // namespace zserio
285 
286 #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:516
typename IBasicReflectable< ALLOC >::ConstPtr IBasicReflectableConstPtr
Definition: IReflectable.h:519
static bool hasChoice(SchemaType schemaType)
static bool isCompound(SchemaType schemaType)
Definition: TypeInfoUtil.cpp:6