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