Zserio C++ runtime library  1.0.1
Built for Zserio 2.14.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  return anyValue;
188  }
189  // else it's a no match
190  }
191 
192  throw CppRuntimeException("ZserioTreeCreator: Cannot create enum '")
193  << typeInfo.getSchemaName() << "' from string value '" << stringValue << "'!";
194 }
195 
196 template <typename ALLOC>
197 AnyHolder<ALLOC> makeAnyEnumValue(
198  const string<ALLOC>& stringValue, const IBasicTypeInfo<ALLOC>& typeInfo, const ALLOC& allocator)
199 {
200  return makeAnyEnumValue(StringView(stringValue), typeInfo, allocator);
201 }
202 
203 template <typename ALLOC>
204 AnyHolder<ALLOC> makeAnyEnumValue(
205  const char* stringValue, const IBasicTypeInfo<ALLOC>& typeInfo, const ALLOC& allocator)
206 {
207  return makeAnyEnumValue(StringView(stringValue), typeInfo, allocator);
208 }
209 
210 template <typename T, typename ALLOC, typename std::enable_if<std::is_enum<T>::value, int>::type = 0>
211 AnyHolder<ALLOC> makeAnyEnumValue(T enumValue, const IBasicTypeInfo<ALLOC>&, const ALLOC& allocator)
212 {
213  return AnyHolder<ALLOC>(enumValue, allocator);
214 }
215 
216 template <typename T, typename ALLOC, typename std::enable_if<!std::is_enum<T>::value, int>::type = 0>
217 AnyHolder<ALLOC> makeAnyEnumValue(T enumRawValue, const IBasicTypeInfo<ALLOC>& typeInfo, const ALLOC& allocator)
218 {
219  return makeAnyValue(typeInfo.getUnderlyingType(), enumRawValue, allocator);
220 }
221 
222 template <typename ALLOC>
223 AnyHolder<ALLOC> parseBitmaskStringValue(
224  StringView stringValue, const IBasicTypeInfo<ALLOC>& typeInfo, const ALLOC& allocator)
225 {
226  uint64_t value = 0;
227  size_t pos = 0;
228  while (pos < stringValue.size())
229  {
230  bool match = false;
231  const size_t available = stringValue.size() - pos;
232  for (const auto& itemInfo : typeInfo.getBitmaskValues())
233  {
234  if (available >= itemInfo.schemaName.size() &&
235  stringValue.substr(pos, itemInfo.schemaName.size()) == itemInfo.schemaName)
236  {
237  const size_t newPos = pos + itemInfo.schemaName.size();
238  // check that the identifier really ends here
239  if (newPos == stringValue.size() || stringValue[newPos] == ' ' || stringValue[newPos] == '|')
240  {
241  value |= itemInfo.value;
242  if (newPos == stringValue.size())
243  return makeAnyValue(typeInfo.getUnderlyingType(), value, allocator); // end of string
244  match = true;
245  pos += itemInfo.schemaName.size();
246  break;
247  }
248  }
249  }
250 
251  if (!match)
252  break;
253 
254  while (pos < stringValue.size() && stringValue[pos] == ' ')
255  ++pos;
256 
257  if (pos < stringValue.size() && stringValue[pos] == '|')
258  ++pos;
259 
260  while (pos < stringValue.size() && stringValue[pos] == ' ')
261  ++pos;
262  }
263 
264  // invalid format or identifier
265  return AnyHolder<ALLOC>(allocator);
266 }
267 
268 template <typename ALLOC>
269 AnyHolder<ALLOC> parseBitmaskNumericStringValue(
270  const char* stringValue, const IBasicTypeInfo<ALLOC>& typeInfo, const ALLOC& allocator)
271 {
272  char* pEnd = nullptr;
273  errno = 0;
274  uint64_t value = std::strtoull(stringValue, &pEnd, 10);
275  if (errno == ERANGE)
276  return AnyHolder<ALLOC>(allocator);
277  return makeAnyValue(typeInfo.getUnderlyingType(), value, allocator);
278 }
279 
280 template <typename ALLOC>
281 AnyHolder<ALLOC> makeAnyBitmaskValue(
282  StringView stringValue, const IBasicTypeInfo<ALLOC>& typeInfo, const ALLOC& allocator)
283 {
284  if (!stringValue.empty())
285  {
286  const char firstChar = stringValue[0];
287  if ((firstChar >= 'A' && firstChar <= 'Z') || (firstChar >= 'a' && firstChar <= 'z') ||
288  firstChar == '_')
289  {
290  AnyHolder<ALLOC> anyValue = parseBitmaskStringValue(stringValue, typeInfo, allocator);
291  if (anyValue.hasValue())
292  return anyValue;
293  }
294  else if (firstChar >= '0' && firstChar <= '9') // bitmask can be only unsigned
295  {
296  // ensure zero-terminated string
297  const string<ALLOC> numericStringValue = toString(stringValue, allocator);
298  AnyHolder<ALLOC> anyValue =
299  parseBitmaskNumericStringValue(numericStringValue.c_str(), typeInfo, allocator);
300  if (anyValue.hasValue())
301  return anyValue;
302  }
303  }
304 
305  throw CppRuntimeException("ZserioTreeCreator: Cannot create bitmask '")
306  << typeInfo.getSchemaName() << "' from string value '" << stringValue << "'!";
307 }
308 
309 template <typename ALLOC>
310 AnyHolder<ALLOC> makeAnyBitmaskValue(
311  const string<ALLOC>& stringValue, const IBasicTypeInfo<ALLOC>& typeInfo, const ALLOC& allocator)
312 {
313  return makeAnyBitmaskValue(StringView(stringValue), typeInfo, allocator);
314 }
315 
316 template <typename ALLOC>
317 AnyHolder<ALLOC> makeAnyBitmaskValue(
318  const char* stringValue, const IBasicTypeInfo<ALLOC>& typeInfo, const ALLOC& allocator)
319 {
320  return makeAnyBitmaskValue(StringView(stringValue), typeInfo, allocator);
321 }
322 
323 template <typename T, typename ALLOC, typename std::enable_if<is_bitmask<T>::value, int>::type = 0>
324 AnyHolder<ALLOC> makeAnyBitmaskValue(T bitmaskValue, const IBasicTypeInfo<ALLOC>&, const ALLOC& allocator)
325 {
326  return AnyHolder<ALLOC>(bitmaskValue, allocator);
327 }
328 
329 template <typename T, typename ALLOC, typename std::enable_if<!is_bitmask<T>::value, int>::type = 0>
330 AnyHolder<ALLOC> makeAnyBitmaskValue(
331  T bitmaskRawValue, const IBasicTypeInfo<ALLOC>& typeInfo, const ALLOC& allocator)
332 {
333  return makeAnyValue(typeInfo.getUnderlyingType(), bitmaskRawValue, allocator);
334 }
335 
336 template <typename T, typename ALLOC>
337 AnyHolder<ALLOC> makeAnyValue(const IBasicTypeInfo<ALLOC>& typeInfo, T&& value, const ALLOC& allocator)
338 {
339  switch (typeInfo.getCppType())
340  {
341  case CppType::BOOL:
342  return makeAnyBoolValue<bool>(std::forward<T>(value), allocator);
343  case CppType::UINT8:
344  return makeAnyIntegralValue<uint8_t>(std::forward<T>(value), allocator);
345  case CppType::UINT16:
346  return makeAnyIntegralValue<uint16_t>(std::forward<T>(value), allocator);
347  case CppType::UINT32:
348  return makeAnyIntegralValue<uint32_t>(std::forward<T>(value), allocator);
349  case CppType::UINT64:
350  return makeAnyIntegralValue<uint64_t>(std::forward<T>(value), allocator);
351  case CppType::INT8:
352  return makeAnyIntegralValue<int8_t>(std::forward<T>(value), allocator);
353  case CppType::INT16:
354  return makeAnyIntegralValue<int16_t>(std::forward<T>(value), allocator);
355  case CppType::INT32:
356  return makeAnyIntegralValue<int32_t>(std::forward<T>(value), allocator);
357  case CppType::INT64:
358  return makeAnyIntegralValue<int64_t>(std::forward<T>(value), allocator);
359  case CppType::FLOAT:
360  return makeAnyFloatingValue<float>(std::forward<T>(value), allocator);
361  case CppType::DOUBLE:
362  return makeAnyFloatingValue<double>(std::forward<T>(value), allocator);
363  case CppType::STRING:
364  return makeAnyStringValue(std::forward<T>(value), allocator);
365  case CppType::ENUM:
366  return makeAnyEnumValue(std::forward<T>(value), typeInfo, allocator);
367  case CppType::BITMASK:
368  return makeAnyBitmaskValue(std::forward<T>(value), typeInfo, allocator);
369  default:
370  return AnyHolder<ALLOC>(std::forward<T>(value), allocator);
371  }
372 }
373 
374 // overload for values which are already in AnyHolder
375 template <typename ALLOC>
376 AnyHolder<ALLOC> makeAnyValue(const IBasicTypeInfo<ALLOC>&, AnyHolder<ALLOC>&& anyValue, const ALLOC&)
377 {
378  return std::move(anyValue);
379 }
380 
381 enum class CreatorState : uint8_t
382 {
383  BEFORE_ROOT,
384  IN_COMPOUND,
385  IN_ARRAY
386 };
387 
388 } // namespace detail
389 
398 CppRuntimeException& operator<<(CppRuntimeException& exception, detail::CreatorState state);
399 
403 template <typename ALLOC>
405 {
406 public:
412  explicit BasicZserioTreeCreator(const IBasicTypeInfo<ALLOC>& typeInfo, const ALLOC& allocator = ALLOC());
413 
417  void beginRoot();
418 
427 
435  void beginArray(const string<ALLOC>& name);
436 
442  void endArray();
443 
451  void beginCompound(const string<ALLOC>& name);
452 
458  void endCompound();
459 
468  template <typename T>
469  void setValue(const string<ALLOC>& name, T&& value);
470 
481  void setValue(const string<ALLOC>& name, std::nullptr_t nullValue);
482 
492  const IBasicTypeInfo<ALLOC>& getFieldType(const string<ALLOC>& name) const;
493 
499  void beginCompoundElement();
500 
506  void endCompoundElement();
507 
515  template <typename T>
516  void addValueElement(T&& value);
517 
525  const IBasicTypeInfo<ALLOC>& getElementType() const;
526 
527 private:
529 
530  const IBasicTypeInfo<ALLOC>& getTypeInfo() const;
531  const BasicFieldInfo<ALLOC>& findFieldInfo(const IBasicTypeInfo<ALLOC>& typeInfo, StringView name) const;
532 
533  template <typename T>
534  AnyHolder<ALLOC> makeAnyValue(const IBasicTypeInfo<ALLOC>& typeInfo, T&& value) const;
535 
536  const IBasicTypeInfo<ALLOC>& m_typeInfo;
538  vector<IBasicReflectablePtr<ALLOC>, ALLOC> m_valueStack;
539  detail::CreatorState m_state = detail::CreatorState::BEFORE_ROOT;
540 };
541 
544 
545 template <typename ALLOC>
547  const IBasicTypeInfo<ALLOC>& typeInfo, const ALLOC& allocator) :
548  AllocatorHolder<ALLOC>(allocator),
549  m_typeInfo(typeInfo),
550  m_fieldInfoStack(allocator),
551  m_valueStack(allocator)
552 {}
553 
554 template <typename ALLOC>
556 {
557  if (m_state != detail::CreatorState::BEFORE_ROOT)
558  throw CppRuntimeException("ZserioTreeCreator: Cannot begin root in state '") << m_state << "'!";
559 
560  m_valueStack.push_back(m_typeInfo.createInstance(get_allocator()));
561  m_state = detail::CreatorState::IN_COMPOUND;
562 }
563 
564 template <typename ALLOC>
566 {
567  if (m_state != detail::CreatorState::IN_COMPOUND || m_valueStack.size() != 1)
568  throw CppRuntimeException("ZserioTreeCreator: Cannot end root in state '") << m_state << "'!";
569 
570  m_state = detail::CreatorState::BEFORE_ROOT;
571  auto value = m_valueStack.back();
572  m_valueStack.pop_back();
573  return value;
574 }
575 
576 template <typename ALLOC>
578 {
579  if (m_state != detail::CreatorState::IN_COMPOUND)
580  throw CppRuntimeException("ZserioTreeCreator: Cannot begin array in state '") << m_state << "'!";
581 
582  const auto& parentTypeInfo = getTypeInfo();
583  const auto& fieldInfo = findFieldInfo(parentTypeInfo, name);
584  if (!fieldInfo.isArray)
585  {
586  throw CppRuntimeException("ZserioTreeCreator: Member '")
587  << fieldInfo.schemaName << "' is not an array!";
588  }
589 
590  m_fieldInfoStack.push_back(fieldInfo);
591 
592  // note that we cannot just call getField() in case that the array is not optional like we do it in
593  // setValue() and beginCompound() methods because in case of arrays we would join multiple arrays together
594  // when this method is called multiple times with the same name - thus we will just create a new array
595  //
596  // moreover we need to properly initialize arrays of dynamic bit fields
597  // see https://github.com/ndsev/zserio/issues/414
598  m_valueStack.push_back(m_valueStack.back()->createField(name));
599 
600  m_state = detail::CreatorState::IN_ARRAY;
601 }
602 
603 template <typename ALLOC>
605 {
606  if (m_state != detail::CreatorState::IN_ARRAY)
607  throw CppRuntimeException("ZserioTreeCreator: Cannot end array in state '") << m_state << "'!";
608 
609  m_fieldInfoStack.pop_back();
610  m_valueStack.pop_back();
611  m_state = detail::CreatorState::IN_COMPOUND;
612 }
613 
614 template <typename ALLOC>
616 {
617  if (m_state != detail::CreatorState::IN_COMPOUND)
618  throw CppRuntimeException("ZserioTreeCreator: Cannot begin compound in state '") << m_state << "'!";
619 
620  const auto& parentTypeInfo = getTypeInfo();
621  const auto& fieldInfo = findFieldInfo(parentTypeInfo, name);
622  if (fieldInfo.isArray)
623  throw CppRuntimeException("ZserioTreeCreator: Member '") << fieldInfo.schemaName << "' is an array!";
624 
625  if (!TypeInfoUtil::isCompound(fieldInfo.typeInfo.getCppType()))
626  {
627  throw CppRuntimeException("ZserioTreeCreator: Member '")
628  << fieldInfo.schemaName << "' is not a compound!";
629  }
630 
631  m_fieldInfoStack.push_back(fieldInfo);
632  if (TypeInfoUtil::hasChoice(parentTypeInfo.getCppType()) || fieldInfo.isOptional)
633  {
634  // optional field, or field within choice or union -> create the new compound
635  m_valueStack.push_back(m_valueStack.back()->createField(name));
636  }
637  else
638  {
639  m_valueStack.push_back(m_valueStack.back()->getField(name));
640  }
641 
642  m_state = detail::CreatorState::IN_COMPOUND;
643 }
644 
645 template <typename ALLOC>
647 {
648  if (m_state != detail::CreatorState::IN_COMPOUND || m_fieldInfoStack.empty())
649  {
650  throw CppRuntimeException("ZserioTreeCreator: Cannot end compound in state '")
651  << m_state << "'" << (m_fieldInfoStack.empty() ? ", expecting endRoot!" : "!'");
652  }
653 
654  const BasicFieldInfo<ALLOC>& fieldInfo = m_fieldInfoStack.back();
655  if (fieldInfo.isArray)
656  throw CppRuntimeException("ZserioTreeCreator: Cannot end compound, it's an array element!");
657 
658  m_fieldInfoStack.pop_back();
659  m_valueStack.pop_back();
660 }
661 
662 template <typename ALLOC>
663 template <typename T>
665 {
666  if (m_state != detail::CreatorState::IN_COMPOUND)
667  throw CppRuntimeException("ZserioTreeCreator: Cannot set value in state '") << m_state << "'!";
668 
669  const BasicFieldInfo<ALLOC>& fieldInfo = findFieldInfo(getTypeInfo(), name);
670  if (fieldInfo.isArray)
671  {
672  throw CppRuntimeException("ZserioTreeCreator: Expecting array in member '")
673  << fieldInfo.schemaName << "'!";
674  }
675 
676  m_valueStack.back()->setField(
677  fieldInfo.schemaName, makeAnyValue(fieldInfo.typeInfo, std::forward<T>(value)));
678 }
679 
680 template <typename ALLOC>
681 void BasicZserioTreeCreator<ALLOC>::setValue(const string<ALLOC>& name, std::nullptr_t nullValue)
682 {
683  if (m_state != detail::CreatorState::IN_COMPOUND)
684  {
685  throw CppRuntimeException("ZserioTreeCreator: Cannot set value (null) in state '") << m_state << "'!";
686  }
687 
688  const BasicFieldInfo<ALLOC>& fieldInfo = findFieldInfo(getTypeInfo(), name);
689  if (fieldInfo.isOptional)
690  {
691  // reset an optional field
692  m_valueStack.back()->setField(fieldInfo.schemaName, AnyHolder<ALLOC>(nullValue, get_allocator()));
693  }
694  else
695  {
696  // reset non-optional field with default-constructed value
697  // (classes generated in C++ do not support null values)
698  m_valueStack.back()->createField(fieldInfo.schemaName);
699  }
700 }
701 
702 template <typename ALLOC>
704 {
705  if (m_state != detail::CreatorState::IN_COMPOUND)
706  throw CppRuntimeException("ZserioTreeCreator: Cannot get field type in state '") << m_state << "'!";
707 
708  return findFieldInfo(getTypeInfo(), name).typeInfo;
709 }
710 
711 template <typename ALLOC>
713 {
714  if (m_state != detail::CreatorState::IN_ARRAY)
715  {
716  throw CppRuntimeException("ZserioTreeCreator: Cannot begin compound element in state '")
717  << m_state << "'!";
718  }
719 
720  const BasicFieldInfo<ALLOC>& fieldInfo = m_fieldInfoStack.back();
721  if (!TypeInfoUtil::isCompound(fieldInfo.typeInfo.getCppType()))
722  {
723  throw CppRuntimeException("ZserioTreeCreator: Member '")
724  << fieldInfo.schemaName << "' is not a compound!";
725  }
726 
727  auto compoundArray = m_valueStack.back();
728  compoundArray->resize(compoundArray->size() + 1);
729  m_valueStack.push_back(compoundArray->at(compoundArray->size() - 1));
730  m_state = detail::CreatorState::IN_COMPOUND;
731 }
732 
733 template <typename ALLOC>
735 {
736  if (m_state != detail::CreatorState::IN_COMPOUND || m_fieldInfoStack.empty())
737  {
738  throw CppRuntimeException("ZserioTreeCreator: Cannot end compound element in state '")
739  << m_state << (m_fieldInfoStack.empty() ? ", expecting endRoot!" : "'!");
740  }
741 
742  const BasicFieldInfo<ALLOC>& fieldInfo = m_fieldInfoStack.back();
743  if (!fieldInfo.isArray)
744  throw CppRuntimeException("ZserioTreeCreator: Cannot end compound element, not in array!");
745 
746  m_valueStack.pop_back();
747  m_state = detail::CreatorState::IN_ARRAY;
748 }
749 
750 template <typename ALLOC>
751 template <typename T>
753 {
754  if (m_state != detail::CreatorState::IN_ARRAY)
755  {
756  throw CppRuntimeException("ZserioTreeCreator: Cannot add value element in state '") << m_state << "'!";
757  }
758 
759  const BasicFieldInfo<ALLOC>& fieldInfo = m_fieldInfoStack.back();
760  m_valueStack.back()->append(makeAnyValue(fieldInfo.typeInfo, std::forward<T>(value)));
761 }
762 
763 template <typename ALLOC>
765 {
766  if (m_state != detail::CreatorState::IN_ARRAY)
767  {
768  throw CppRuntimeException("ZserioTreeCreator: Cannot get element type in state '") << m_state << "'!";
769  }
770 
771  return m_fieldInfoStack.back().get().typeInfo;
772 }
773 
774 template <typename ALLOC>
776 {
777  return m_fieldInfoStack.empty() ? m_typeInfo : m_fieldInfoStack.back().get().typeInfo;
778 }
779 
780 template <typename ALLOC>
781 const BasicFieldInfo<ALLOC>& BasicZserioTreeCreator<ALLOC>::findFieldInfo(
782  const IBasicTypeInfo<ALLOC>& typeInfo, StringView name) const
783 {
784  Span<const BasicFieldInfo<ALLOC>> fields = typeInfo.getFields();
785  auto found_it = std::find_if(fields.begin(), fields.end(), [name](const BasicFieldInfo<ALLOC>& field) {
786  return field.schemaName == name;
787  });
788  if (found_it == fields.end())
789  {
790  throw CppRuntimeException("ZserioTreeCreator: Member '")
791  << name << "' not found in '" << typeInfo.getSchemaName() << "'!";
792  }
793 
794  return *found_it;
795 }
796 
797 template <typename ALLOC>
798 template <typename T>
799 AnyHolder<ALLOC> BasicZserioTreeCreator<ALLOC>::makeAnyValue(
800  const IBasicTypeInfo<ALLOC>& typeInfo, T&& value) const
801 {
802  return detail::makeAnyValue(typeInfo, std::forward<T>(value), get_allocator());
803 }
804 
805 } // namespace zserio
806 
807 #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:936
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:435
string< ALLOC > toString(T value, const ALLOC &allocator=ALLOC())
typename IBasicReflectable< ALLOC >::Ptr IBasicReflectablePtr
Definition: IReflectable.h:516
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)