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