Zserio C++ runtime library  1.1.0
Built for Zserio 2.15.0
ZserioTreeCreator.h
Go to the documentation of this file.
1 #ifndef ZSERIO_ZSERIO_TREE_CREATOR_H_INC
2 #define ZSERIO_ZSERIO_TREE_CREATOR_H_INC
3 
4 #include <cerrno>
5 #include <cstdlib>
6 #include <limits>
7 #include <type_traits>
8 
9 #include "zserio/BitBuffer.h"
11 #include "zserio/IReflectable.h"
12 #include "zserio/ITypeInfo.h"
13 #include "zserio/StringView.h"
14 #include "zserio/Traits.h"
15 #include "zserio/TypeInfoUtil.h"
16 #include "zserio/Types.h"
17 #include "zserio/Vector.h"
18 
19 namespace zserio
20 {
21 
22 namespace detail
23 {
24 
25 template <typename T, typename ALLOC>
26 AnyHolder<ALLOC> makeAnyValue(const IBasicTypeInfo<ALLOC>& typeInfo, T&& value, const ALLOC& allocator);
27 
28 template <typename T, typename U,
29  typename std::enable_if<std::is_unsigned<typename std::decay<U>::type>::value, int>::type = 0>
30 bool checkArithmeticValueRanges(U value)
31 {
32  // value is unsigned
33  return (value <= static_cast<U>(std::numeric_limits<T>::max()));
34 }
35 
36 template <typename T, typename U,
37  typename std::enable_if<std::is_signed<typename std::decay<U>::type>::value &&
38  std::is_signed<typename std::decay<T>::type>::value,
39  int>::type = 0>
40 bool checkArithmeticValueRanges(U value)
41 {
42  // value is signed and it is converted to signed value
43  return (static_cast<int64_t>(value) >= static_cast<int64_t>(std::numeric_limits<T>::min()) &&
44  static_cast<int64_t>(value) <= static_cast<int64_t>(std::numeric_limits<T>::max()));
45 }
46 
47 template <typename T, typename U,
48  typename std::enable_if<std::is_signed<typename std::decay<U>::type>::value &&
49  std::is_unsigned<typename std::decay<T>::type>::value,
50  int>::type = 0>
51 bool checkArithmeticValueRanges(U value)
52 {
53  // value is signed and it is converted to unsigned value
54  return (value >= 0 && static_cast<uint64_t>(value) <= static_cast<uint64_t>(std::numeric_limits<T>::max()));
55 }
56 
57 template <typename T, typename ALLOC>
58 AnyHolder<ALLOC> makeAnyBoolValue(bool value, const ALLOC& allocator)
59 {
60  return AnyHolder<ALLOC>(static_cast<T>(value), allocator);
61 }
62 
63 template <typename T, typename U, typename ALLOC>
64 AnyHolder<ALLOC> makeAnyBoolValue(const U& value, const ALLOC&)
65 {
66  throw CppRuntimeException("ZserioTreeCreator: Value '") << value << "' cannot be converted to bool value!";
67 }
68 
69 template <typename T, typename ALLOC>
70 AnyHolder<ALLOC> makeAnyIntegralValue(bool value, const ALLOC&)
71 {
72  throw CppRuntimeException("ZserioTreeCreator: Bool value '")
73  << value << "' cannot be converted to integral type!";
74 }
75 
76 template <typename T, typename U, typename ALLOC,
77  typename std::enable_if<std::is_integral<typename std::decay<U>::type>::value, int>::type = 0>
78 AnyHolder<ALLOC> makeAnyIntegralValue(U value, const ALLOC& allocator)
79 {
80  // check ranges of integers
81  if (!checkArithmeticValueRanges<T>(value))
82  {
83  throw CppRuntimeException("ZserioTreeCreator: Integral value '")
84  << value << "' overflow (<" << std::numeric_limits<T>::min() << ", "
85  << std::numeric_limits<T>::max() << ">)!";
86  }
87 
88  return AnyHolder<ALLOC>(static_cast<T>(value), allocator);
89 }
90 
91 template <typename T, typename U, typename ALLOC,
92  typename std::enable_if<!std::is_integral<typename std::decay<U>::type>::value, int>::type = 0>
93 AnyHolder<ALLOC> makeAnyIntegralValue(const U& value, const ALLOC&)
94 {
95  throw CppRuntimeException("ZserioTreeCreator: Value '")
96  << value << "' cannot be converted to integral value!";
97 }
98 
99 template <typename T, typename ALLOC>
100 AnyHolder<ALLOC> makeAnyFloatingValue(bool value, const ALLOC&)
101 {
102  throw CppRuntimeException("ZserioTreeCreator: Bool value '")
103  << value << "' cannot be converted to floating type!";
104 }
105 
106 template <typename T, typename U, typename ALLOC,
107  typename std::enable_if<std::is_arithmetic<typename std::decay<U>::type>::value, int>::type = 0>
108 AnyHolder<ALLOC> makeAnyFloatingValue(U value, const ALLOC& allocator)
109 {
110  // allow conversion integers to floats
111  return AnyHolder<ALLOC>(static_cast<T>(value), allocator);
112 }
113 
114 template <typename T, typename U, typename ALLOC,
115  typename std::enable_if<!std::is_arithmetic<typename std::decay<U>::type>::value, int>::type = 0>
116 AnyHolder<ALLOC> makeAnyFloatingValue(const U& value, const ALLOC&)
117 {
118  throw CppRuntimeException("ZserioTreeCreator: Value '")
119  << value << "' cannot be converted to floating value!";
120 }
121 
122 template <typename ALLOC>
123 AnyHolder<ALLOC> makeAnyStringValue(const string<ALLOC>& value, const ALLOC& allocator)
124 {
125  return AnyHolder<ALLOC>(value, allocator);
126 }
127 
128 template <typename ALLOC>
129 AnyHolder<ALLOC> makeAnyStringValue(string<ALLOC>&& value, const ALLOC& allocator)
130 {
131  return AnyHolder<ALLOC>(std::move(value), allocator);
132 }
133 
134 template <typename ALLOC>
135 AnyHolder<ALLOC> makeAnyStringValue(StringView value, const ALLOC& allocator)
136 {
137  return AnyHolder<ALLOC>(toString(value, allocator), allocator);
138 }
139 
140 template <typename ALLOC>
141 AnyHolder<ALLOC> makeAnyStringValue(const char* value, const ALLOC& allocator)
142 {
143  return makeAnyStringValue(StringView(value), allocator);
144 }
145 
146 template <typename T, typename ALLOC>
147 AnyHolder<ALLOC> makeAnyStringValue(const T&, const ALLOC&)
148 {
149  throw CppRuntimeException("ZserioTreeCreator: Trying to make any string value from unsupported type!");
150 }
151 
152 template <typename ALLOC>
153 AnyHolder<ALLOC> parseEnumStringValue(
154  StringView stringValue, const IBasicTypeInfo<ALLOC>& typeInfo, const ALLOC& allocator)
155 {
156  for (const auto& itemInfo : typeInfo.getEnumItems())
157  {
158  if (itemInfo.schemaName == stringValue)
159  {
160  if (TypeInfoUtil::isSigned(typeInfo.getUnderlyingType().getCppType()))
161  {
162  return makeAnyValue(
163  typeInfo.getUnderlyingType(), static_cast<int64_t>(itemInfo.value), allocator);
164  }
165  else
166  {
167  return makeAnyValue(typeInfo.getUnderlyingType(), itemInfo.value, allocator);
168  }
169  }
170  }
171 
172  return AnyHolder<ALLOC>(allocator);
173 }
174 
175 template <typename ALLOC>
176 AnyHolder<ALLOC> makeAnyEnumValue(
177  StringView stringValue, const IBasicTypeInfo<ALLOC>& typeInfo, const ALLOC& allocator)
178 {
179  if (!stringValue.empty())
180  {
181  const char firstChar = stringValue[0];
182  if ((firstChar >= 'A' && firstChar <= 'Z') || (firstChar >= 'a' && firstChar <= 'z') ||
183  firstChar == '_')
184  {
185  AnyHolder<ALLOC> anyValue = parseEnumStringValue(stringValue, typeInfo, allocator);
186  if (anyValue.hasValue())
187  {
188  return anyValue;
189  }
190  }
191  // else it's a no match
192  }
193 
194  throw CppRuntimeException("ZserioTreeCreator: Cannot create enum '")
195  << typeInfo.getSchemaName() << "' from string value '" << stringValue << "'!";
196 }
197 
198 template <typename ALLOC>
199 AnyHolder<ALLOC> makeAnyEnumValue(
200  const string<ALLOC>& stringValue, const IBasicTypeInfo<ALLOC>& typeInfo, const ALLOC& allocator)
201 {
202  return makeAnyEnumValue(StringView(stringValue), typeInfo, allocator);
203 }
204 
205 template <typename ALLOC>
206 AnyHolder<ALLOC> makeAnyEnumValue(
207  const char* stringValue, const IBasicTypeInfo<ALLOC>& typeInfo, const ALLOC& allocator)
208 {
209  return makeAnyEnumValue(StringView(stringValue), typeInfo, allocator);
210 }
211 
212 template <typename T, typename ALLOC, typename std::enable_if<std::is_enum<T>::value, int>::type = 0>
213 AnyHolder<ALLOC> makeAnyEnumValue(T enumValue, const IBasicTypeInfo<ALLOC>&, const ALLOC& allocator)
214 {
215  return AnyHolder<ALLOC>(enumValue, allocator);
216 }
217 
218 template <typename T, typename ALLOC, typename std::enable_if<!std::is_enum<T>::value, int>::type = 0>
219 AnyHolder<ALLOC> makeAnyEnumValue(T enumRawValue, const IBasicTypeInfo<ALLOC>& typeInfo, const ALLOC& allocator)
220 {
221  return makeAnyValue(typeInfo.getUnderlyingType(), enumRawValue, allocator);
222 }
223 
224 template <typename ALLOC>
225 AnyHolder<ALLOC> parseBitmaskStringValue(
226  StringView stringValue, const IBasicTypeInfo<ALLOC>& typeInfo, const ALLOC& allocator)
227 {
228  uint64_t value = 0;
229  size_t pos = 0;
230  while (pos < stringValue.size())
231  {
232  bool match = false;
233  const size_t available = stringValue.size() - pos;
234  for (const auto& itemInfo : typeInfo.getBitmaskValues())
235  {
236  if (available >= itemInfo.schemaName.size() &&
237  stringValue.substr(pos, itemInfo.schemaName.size()) == itemInfo.schemaName)
238  {
239  const size_t newPos = pos + itemInfo.schemaName.size();
240  // check that the identifier really ends here
241  if (newPos == stringValue.size() || stringValue[newPos] == ' ' || stringValue[newPos] == '|')
242  {
243  value |= itemInfo.value;
244  if (newPos == stringValue.size())
245  {
246  return makeAnyValue(typeInfo.getUnderlyingType(), value, allocator); // end of string
247  }
248  match = true;
249  pos += itemInfo.schemaName.size();
250  break;
251  }
252  }
253  }
254 
255  if (!match)
256  {
257  break;
258  }
259 
260  while (pos < stringValue.size() && stringValue[pos] == ' ')
261  {
262  ++pos;
263  }
264 
265  if (pos < stringValue.size() && stringValue[pos] == '|')
266  {
267  ++pos;
268  }
269 
270  while (pos < stringValue.size() && stringValue[pos] == ' ')
271  {
272  ++pos;
273  }
274  }
275 
276  // invalid format or identifier
277  return AnyHolder<ALLOC>(allocator);
278 }
279 
280 template <typename ALLOC>
281 AnyHolder<ALLOC> parseBitmaskNumericStringValue(
282  const char* stringValue, const IBasicTypeInfo<ALLOC>& typeInfo, const ALLOC& allocator)
283 {
284  char* pEnd = nullptr;
285  errno = 0;
286  uint64_t value = std::strtoull(stringValue, &pEnd, 10);
287  if (errno == ERANGE)
288  {
289  return AnyHolder<ALLOC>(allocator);
290  }
291  return makeAnyValue(typeInfo.getUnderlyingType(), value, allocator);
292 }
293 
294 template <typename ALLOC>
295 AnyHolder<ALLOC> makeAnyBitmaskValue(
296  StringView stringValue, const IBasicTypeInfo<ALLOC>& typeInfo, const ALLOC& allocator)
297 {
298  if (!stringValue.empty())
299  {
300  const char firstChar = stringValue[0];
301  if ((firstChar >= 'A' && firstChar <= 'Z') || (firstChar >= 'a' && firstChar <= 'z') ||
302  firstChar == '_')
303  {
304  AnyHolder<ALLOC> anyValue = parseBitmaskStringValue(stringValue, typeInfo, allocator);
305  if (anyValue.hasValue())
306  {
307  return anyValue;
308  }
309  }
310  else if (firstChar >= '0' && firstChar <= '9') // bitmask can be only unsigned
311  {
312  // ensure zero-terminated string
313  const string<ALLOC> numericStringValue = toString(stringValue, allocator);
314  AnyHolder<ALLOC> anyValue =
315  parseBitmaskNumericStringValue(numericStringValue.c_str(), typeInfo, allocator);
316  if (anyValue.hasValue())
317  {
318  return anyValue;
319  }
320  }
321  }
322 
323  throw CppRuntimeException("ZserioTreeCreator: Cannot create bitmask '")
324  << typeInfo.getSchemaName() << "' from string value '" << stringValue << "'!";
325 }
326 
327 template <typename ALLOC>
328 AnyHolder<ALLOC> makeAnyBitmaskValue(
329  const string<ALLOC>& stringValue, const IBasicTypeInfo<ALLOC>& typeInfo, const ALLOC& allocator)
330 {
331  return makeAnyBitmaskValue(StringView(stringValue), typeInfo, allocator);
332 }
333 
334 template <typename ALLOC>
335 AnyHolder<ALLOC> makeAnyBitmaskValue(
336  const char* stringValue, const IBasicTypeInfo<ALLOC>& typeInfo, const ALLOC& allocator)
337 {
338  return makeAnyBitmaskValue(StringView(stringValue), typeInfo, allocator);
339 }
340 
341 template <typename T, typename ALLOC, typename std::enable_if<is_bitmask<T>::value, int>::type = 0>
342 AnyHolder<ALLOC> makeAnyBitmaskValue(T bitmaskValue, const IBasicTypeInfo<ALLOC>&, const ALLOC& allocator)
343 {
344  return AnyHolder<ALLOC>(bitmaskValue, allocator);
345 }
346 
347 template <typename T, typename ALLOC, typename std::enable_if<!is_bitmask<T>::value, int>::type = 0>
348 AnyHolder<ALLOC> makeAnyBitmaskValue(
349  T bitmaskRawValue, const IBasicTypeInfo<ALLOC>& typeInfo, const ALLOC& allocator)
350 {
351  return makeAnyValue(typeInfo.getUnderlyingType(), bitmaskRawValue, allocator);
352 }
353 
354 template <typename T, typename ALLOC>
355 AnyHolder<ALLOC> makeAnyValue(const IBasicTypeInfo<ALLOC>& typeInfo, T&& value, const ALLOC& allocator)
356 {
357  switch (typeInfo.getCppType())
358  {
359  case CppType::BOOL:
360  return makeAnyBoolValue<bool>(std::forward<T>(value), allocator);
361  case CppType::UINT8:
362  return makeAnyIntegralValue<uint8_t>(std::forward<T>(value), allocator);
363  case CppType::UINT16:
364  return makeAnyIntegralValue<uint16_t>(std::forward<T>(value), allocator);
365  case CppType::UINT32:
366  return makeAnyIntegralValue<uint32_t>(std::forward<T>(value), allocator);
367  case CppType::UINT64:
368  return makeAnyIntegralValue<uint64_t>(std::forward<T>(value), allocator);
369  case CppType::INT8:
370  return makeAnyIntegralValue<int8_t>(std::forward<T>(value), allocator);
371  case CppType::INT16:
372  return makeAnyIntegralValue<int16_t>(std::forward<T>(value), allocator);
373  case CppType::INT32:
374  return makeAnyIntegralValue<int32_t>(std::forward<T>(value), allocator);
375  case CppType::INT64:
376  return makeAnyIntegralValue<int64_t>(std::forward<T>(value), allocator);
377  case CppType::FLOAT:
378  return makeAnyFloatingValue<float>(std::forward<T>(value), allocator);
379  case CppType::DOUBLE:
380  return makeAnyFloatingValue<double>(std::forward<T>(value), allocator);
381  case CppType::STRING:
382  return makeAnyStringValue(std::forward<T>(value), allocator);
383  case CppType::ENUM:
384  return makeAnyEnumValue(std::forward<T>(value), typeInfo, allocator);
385  case CppType::BITMASK:
386  return makeAnyBitmaskValue(std::forward<T>(value), typeInfo, allocator);
387  default:
388  return AnyHolder<ALLOC>(std::forward<T>(value), allocator);
389  }
390 }
391 
392 // overload for values which are already in AnyHolder
393 template <typename ALLOC>
394 AnyHolder<ALLOC> makeAnyValue(const IBasicTypeInfo<ALLOC>&, AnyHolder<ALLOC>&& anyValue, const ALLOC&)
395 {
396  return std::move(anyValue);
397 }
398 
399 enum class CreatorState : uint8_t
400 {
401  BEFORE_ROOT,
402  IN_COMPOUND,
403  IN_ARRAY
404 };
405 
406 } // namespace detail
407 
416 CppRuntimeException& operator<<(CppRuntimeException& exception, detail::CreatorState state);
417 
421 template <typename ALLOC>
423 {
424 public:
430  explicit BasicZserioTreeCreator(const IBasicTypeInfo<ALLOC>& typeInfo, const ALLOC& allocator = ALLOC());
431 
435  void beginRoot();
436 
445 
453  void beginArray(const string<ALLOC>& name);
454 
460  void endArray();
461 
469  void beginCompound(const string<ALLOC>& name);
470 
476  void endCompound();
477 
486  template <typename T>
487  void setValue(const string<ALLOC>& name, T&& value);
488 
499  void setValue(const string<ALLOC>& name, std::nullptr_t nullValue);
500 
510  const IBasicTypeInfo<ALLOC>& getFieldType(const string<ALLOC>& name) const;
511 
517  void beginCompoundElement();
518 
524  void endCompoundElement();
525 
533  template <typename T>
534  void addValueElement(T&& value);
535 
543  const IBasicTypeInfo<ALLOC>& getElementType() const;
544 
545 private:
547 
548  const IBasicTypeInfo<ALLOC>& getTypeInfo() const;
549  const BasicFieldInfo<ALLOC>& findFieldInfo(const IBasicTypeInfo<ALLOC>& typeInfo, StringView name) const;
550 
551  template <typename T>
552  AnyHolder<ALLOC> makeAnyValue(const IBasicTypeInfo<ALLOC>& typeInfo, T&& value) const;
553 
554  const IBasicTypeInfo<ALLOC>& m_typeInfo;
556  vector<IBasicReflectablePtr<ALLOC>, ALLOC> m_valueStack;
557  detail::CreatorState m_state = detail::CreatorState::BEFORE_ROOT;
558 };
559 
562 
563 template <typename ALLOC>
565  const IBasicTypeInfo<ALLOC>& typeInfo, const ALLOC& allocator) :
566  AllocatorHolder<ALLOC>(allocator),
567  m_typeInfo(typeInfo),
568  m_fieldInfoStack(allocator),
569  m_valueStack(allocator)
570 {}
571 
572 template <typename ALLOC>
574 {
575  if (m_state != detail::CreatorState::BEFORE_ROOT)
576  {
577  throw CppRuntimeException("ZserioTreeCreator: Cannot begin root in state '") << m_state << "'!";
578  }
579 
580  m_valueStack.push_back(m_typeInfo.createInstance(get_allocator()));
581  m_state = detail::CreatorState::IN_COMPOUND;
582 }
583 
584 template <typename ALLOC>
586 {
587  if (m_state != detail::CreatorState::IN_COMPOUND || m_valueStack.size() != 1)
588  {
589  throw CppRuntimeException("ZserioTreeCreator: Cannot end root in state '") << m_state << "'!";
590  }
591 
592  m_state = detail::CreatorState::BEFORE_ROOT;
593  auto value = m_valueStack.back();
594  m_valueStack.pop_back();
595  return value;
596 }
597 
598 template <typename ALLOC>
600 {
601  if (m_state != detail::CreatorState::IN_COMPOUND)
602  {
603  throw CppRuntimeException("ZserioTreeCreator: Cannot begin array in state '") << m_state << "'!";
604  }
605 
606  const auto& parentTypeInfo = getTypeInfo();
607  const auto& fieldInfo = findFieldInfo(parentTypeInfo, name);
608  if (!fieldInfo.isArray)
609  {
610  throw CppRuntimeException("ZserioTreeCreator: Member '")
611  << fieldInfo.schemaName << "' is not an array!";
612  }
613 
614  m_fieldInfoStack.push_back(fieldInfo);
615 
616  // note that we cannot just call getField() in case that the array is not optional like we do it in
617  // setValue() and beginCompound() methods because in case of arrays we would join multiple arrays together
618  // when this method is called multiple times with the same name - thus we will just create a new array
619  //
620  // moreover we need to properly initialize arrays of dynamic bit fields
621  // see https://github.com/ndsev/zserio/issues/414
622  m_valueStack.push_back(m_valueStack.back()->createField(name));
623 
624  m_state = detail::CreatorState::IN_ARRAY;
625 }
626 
627 template <typename ALLOC>
629 {
630  if (m_state != detail::CreatorState::IN_ARRAY)
631  {
632  throw CppRuntimeException("ZserioTreeCreator: Cannot end array in state '") << m_state << "'!";
633  }
634 
635  m_fieldInfoStack.pop_back();
636  m_valueStack.pop_back();
637  m_state = detail::CreatorState::IN_COMPOUND;
638 }
639 
640 template <typename ALLOC>
642 {
643  if (m_state != detail::CreatorState::IN_COMPOUND)
644  {
645  throw CppRuntimeException("ZserioTreeCreator: Cannot begin compound in state '") << m_state << "'!";
646  }
647 
648  const auto& parentTypeInfo = getTypeInfo();
649  const auto& fieldInfo = findFieldInfo(parentTypeInfo, name);
650  if (fieldInfo.isArray)
651  {
652  throw CppRuntimeException("ZserioTreeCreator: Member '") << fieldInfo.schemaName << "' is an array!";
653  }
654 
655  if (!TypeInfoUtil::isCompound(fieldInfo.typeInfo.getCppType()))
656  {
657  throw CppRuntimeException("ZserioTreeCreator: Member '")
658  << fieldInfo.schemaName << "' is not a compound!";
659  }
660 
661  m_fieldInfoStack.push_back(fieldInfo);
662  if (TypeInfoUtil::hasChoice(parentTypeInfo.getCppType()) || fieldInfo.isOptional)
663  {
664  // optional field, or field within choice or union -> create the new compound
665  m_valueStack.push_back(m_valueStack.back()->createField(name));
666  }
667  else
668  {
669  m_valueStack.push_back(m_valueStack.back()->getField(name));
670  }
671 
672  m_state = detail::CreatorState::IN_COMPOUND;
673 }
674 
675 template <typename ALLOC>
677 {
678  if (m_state != detail::CreatorState::IN_COMPOUND || m_fieldInfoStack.empty())
679  {
680  throw CppRuntimeException("ZserioTreeCreator: Cannot end compound in state '")
681  << m_state << "'" << (m_fieldInfoStack.empty() ? ", expecting endRoot!" : "!'");
682  }
683 
684  const BasicFieldInfo<ALLOC>& fieldInfo = m_fieldInfoStack.back();
685  if (fieldInfo.isArray)
686  {
687  throw CppRuntimeException("ZserioTreeCreator: Cannot end compound, it's an array element!");
688  }
689 
690  m_fieldInfoStack.pop_back();
691  m_valueStack.pop_back();
692 }
693 
694 template <typename ALLOC>
695 template <typename T>
697 {
698  if (m_state != detail::CreatorState::IN_COMPOUND)
699  {
700  throw CppRuntimeException("ZserioTreeCreator: Cannot set value in state '") << m_state << "'!";
701  }
702 
703  const BasicFieldInfo<ALLOC>& fieldInfo = findFieldInfo(getTypeInfo(), name);
704  if (fieldInfo.isArray)
705  {
706  throw CppRuntimeException("ZserioTreeCreator: Expecting array in member '")
707  << fieldInfo.schemaName << "'!";
708  }
709 
710  m_valueStack.back()->setField(
711  fieldInfo.schemaName, makeAnyValue(fieldInfo.typeInfo, std::forward<T>(value)));
712 }
713 
714 template <typename ALLOC>
715 void BasicZserioTreeCreator<ALLOC>::setValue(const string<ALLOC>& name, std::nullptr_t nullValue)
716 {
717  if (m_state != detail::CreatorState::IN_COMPOUND)
718  {
719  throw CppRuntimeException("ZserioTreeCreator: Cannot set value (null) in state '") << m_state << "'!";
720  }
721 
722  const BasicFieldInfo<ALLOC>& fieldInfo = findFieldInfo(getTypeInfo(), name);
723  if (fieldInfo.isOptional)
724  {
725  // reset an optional field
726  m_valueStack.back()->setField(fieldInfo.schemaName, AnyHolder<ALLOC>(nullValue, get_allocator()));
727  }
728  else
729  {
730  // reset non-optional field with default-constructed value
731  // (classes generated in C++ do not support null values)
732  m_valueStack.back()->createField(fieldInfo.schemaName);
733  }
734 }
735 
736 template <typename ALLOC>
738 {
739  if (m_state != detail::CreatorState::IN_COMPOUND)
740  {
741  throw CppRuntimeException("ZserioTreeCreator: Cannot get field type in state '") << m_state << "'!";
742  }
743 
744  return findFieldInfo(getTypeInfo(), name).typeInfo;
745 }
746 
747 template <typename ALLOC>
749 {
750  if (m_state != detail::CreatorState::IN_ARRAY)
751  {
752  throw CppRuntimeException("ZserioTreeCreator: Cannot begin compound element in state '")
753  << m_state << "'!";
754  }
755 
756  const BasicFieldInfo<ALLOC>& fieldInfo = m_fieldInfoStack.back();
757  if (!TypeInfoUtil::isCompound(fieldInfo.typeInfo.getCppType()))
758  {
759  throw CppRuntimeException("ZserioTreeCreator: Member '")
760  << fieldInfo.schemaName << "' is not a compound!";
761  }
762 
763  auto compoundArray = m_valueStack.back();
764  compoundArray->resize(compoundArray->size() + 1);
765  m_valueStack.push_back(compoundArray->at(compoundArray->size() - 1));
766  m_state = detail::CreatorState::IN_COMPOUND;
767 }
768 
769 template <typename ALLOC>
771 {
772  if (m_state != detail::CreatorState::IN_COMPOUND || m_fieldInfoStack.empty())
773  {
774  throw CppRuntimeException("ZserioTreeCreator: Cannot end compound element in state '")
775  << m_state << (m_fieldInfoStack.empty() ? ", expecting endRoot!" : "'!");
776  }
777 
778  const BasicFieldInfo<ALLOC>& fieldInfo = m_fieldInfoStack.back();
779  if (!fieldInfo.isArray)
780  {
781  throw CppRuntimeException("ZserioTreeCreator: Cannot end compound element, not in array!");
782  }
783 
784  m_valueStack.pop_back();
785  m_state = detail::CreatorState::IN_ARRAY;
786 }
787 
788 template <typename ALLOC>
789 template <typename T>
791 {
792  if (m_state != detail::CreatorState::IN_ARRAY)
793  {
794  throw CppRuntimeException("ZserioTreeCreator: Cannot add value element in state '") << m_state << "'!";
795  }
796 
797  const BasicFieldInfo<ALLOC>& fieldInfo = m_fieldInfoStack.back();
798  m_valueStack.back()->append(makeAnyValue(fieldInfo.typeInfo, std::forward<T>(value)));
799 }
800 
801 template <typename ALLOC>
803 {
804  if (m_state != detail::CreatorState::IN_ARRAY)
805  {
806  throw CppRuntimeException("ZserioTreeCreator: Cannot get element type in state '") << m_state << "'!";
807  }
808 
809  return m_fieldInfoStack.back().get().typeInfo;
810 }
811 
812 template <typename ALLOC>
814 {
815  return m_fieldInfoStack.empty() ? m_typeInfo : m_fieldInfoStack.back().get().typeInfo;
816 }
817 
818 template <typename ALLOC>
819 const BasicFieldInfo<ALLOC>& BasicZserioTreeCreator<ALLOC>::findFieldInfo(
820  const IBasicTypeInfo<ALLOC>& typeInfo, StringView name) const
821 {
822  Span<const BasicFieldInfo<ALLOC>> fields = typeInfo.getFields();
823  auto found_it = std::find_if(fields.begin(), fields.end(), [name](const BasicFieldInfo<ALLOC>& field) {
824  return field.schemaName == name;
825  });
826  if (found_it == fields.end())
827  {
828  throw CppRuntimeException("ZserioTreeCreator: Member '")
829  << name << "' not found in '" << typeInfo.getSchemaName() << "'!";
830  }
831 
832  return *found_it;
833 }
834 
835 template <typename ALLOC>
836 template <typename T>
837 AnyHolder<ALLOC> BasicZserioTreeCreator<ALLOC>::makeAnyValue(
838  const IBasicTypeInfo<ALLOC>& typeInfo, T&& value) const
839 {
840  return detail::makeAnyValue(typeInfo, std::forward<T>(value), get_allocator());
841 }
842 
843 } // namespace zserio
844 
845 #endif // ZSERIO_ZSERIO_TREE_CREATOR_H_INC
constexpr const_reference back() const noexcept
Definition: StringView.h:220
IBasicReflectablePtr< ALLOC > endRoot()
void beginArray(const string< ALLOC > &name)
const IBasicTypeInfo< ALLOC > & getFieldType(const string< ALLOC > &name) const
const IBasicTypeInfo< ALLOC > & getElementType() const
void setValue(const string< ALLOC > &name, T &&value)
void beginCompound(const string< ALLOC > &name)
BasicZserioTreeCreator(const IBasicTypeInfo< ALLOC > &typeInfo, const ALLOC &allocator=ALLOC())
virtual CppType getCppType() const =0
BasicStringView< char, std::char_traits< char > > StringView
Definition: StringView.h:968
std::basic_string< char, std::char_traits< char >, RebindAlloc< ALLOC, char > > string
Definition: String.h:17
std::vector< T, RebindAlloc< ALLOC, T > > vector
Definition: Vector.h:17
CppRuntimeException & operator<<(CppRuntimeException &exception, const BasicBitBuffer< ALLOC > &bitBuffer)
Definition: BitBuffer.h:455
string< ALLOC > toString(T value, const ALLOC &allocator=ALLOC())
typename IBasicReflectable< ALLOC >::Ptr IBasicReflectablePtr
Definition: IReflectable.h:531
StringView schemaName
Definition: ITypeInfo.h:379
const IBasicTypeInfo< ALLOC > & typeInfo
Definition: ITypeInfo.h:380
static bool hasChoice(SchemaType schemaType)
static bool isCompound(SchemaType schemaType)
Definition: TypeInfoUtil.cpp:6
static bool isSigned(SchemaType schemaType)