Zserio C++ runtime library  1.3.0
Built for Zserio 2.18.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  case CppType::BYTES:
388  case CppType::BIT_BUFFER:
389  case CppType::STRUCT:
390  case CppType::CHOICE:
391  case CppType::UNION:
392  case CppType::SQL_TABLE:
394  case CppType::SERVICE:
395  case CppType::PUBSUB:
396  default:
397  return AnyHolder<ALLOC>(std::forward<T>(value), allocator);
398  }
399 }
400 
401 // overload for values which are already in AnyHolder
402 template <typename ALLOC>
403 AnyHolder<ALLOC> makeAnyValue(const IBasicTypeInfo<ALLOC>&, AnyHolder<ALLOC>&& anyValue, const ALLOC&)
404 {
405  return std::move(anyValue);
406 }
407 
408 enum class CreatorState : uint8_t
409 {
410  BEFORE_ROOT,
411  IN_COMPOUND,
412  IN_ARRAY
413 };
414 
415 } // namespace detail
416 
425 CppRuntimeException& operator<<(CppRuntimeException& exception, detail::CreatorState state);
426 
430 template <typename ALLOC>
432 {
433 public:
439  explicit BasicZserioTreeCreator(const IBasicTypeInfo<ALLOC>& typeInfo, const ALLOC& allocator = ALLOC());
440 
444  void beginRoot();
445 
454 
462  void beginArray(const string<ALLOC>& name);
463 
469  void endArray();
470 
478  void beginCompound(const string<ALLOC>& name);
479 
485  void endCompound();
486 
495  template <typename T>
496  void setValue(const string<ALLOC>& name, T&& value);
497 
508  void setValue(const string<ALLOC>& name, std::nullptr_t nullValue);
509 
519  const IBasicTypeInfo<ALLOC>& getFieldType(const string<ALLOC>& name) const;
520 
526  void beginCompoundElement();
527 
533  void endCompoundElement();
534 
542  template <typename T>
543  void addValueElement(T&& value);
544 
552  const IBasicTypeInfo<ALLOC>& getElementType() const;
553 
554 private:
556 
557  const IBasicTypeInfo<ALLOC>& getTypeInfo() const;
558  const BasicFieldInfo<ALLOC>& findFieldInfo(const IBasicTypeInfo<ALLOC>& typeInfo, StringView name) const;
559 
560  template <typename T>
561  AnyHolder<ALLOC> makeAnyValue(const IBasicTypeInfo<ALLOC>& typeInfo, T&& value) const;
562 
563  const IBasicTypeInfo<ALLOC>& m_typeInfo;
565  vector<IBasicReflectablePtr<ALLOC>, ALLOC> m_valueStack;
566  detail::CreatorState m_state = detail::CreatorState::BEFORE_ROOT;
567 };
568 
571 
572 template <typename ALLOC>
574  const IBasicTypeInfo<ALLOC>& typeInfo, const ALLOC& allocator) :
575  AllocatorHolder<ALLOC>(allocator),
576  m_typeInfo(typeInfo),
577  m_fieldInfoStack(allocator),
578  m_valueStack(allocator)
579 {}
580 
581 template <typename ALLOC>
583 {
584  if (m_state != detail::CreatorState::BEFORE_ROOT)
585  {
586  throw CppRuntimeException("ZserioTreeCreator: Cannot begin root in state '") << m_state << "'!";
587  }
588 
589  m_valueStack.push_back(m_typeInfo.createInstance(get_allocator()));
590  m_state = detail::CreatorState::IN_COMPOUND;
591 }
592 
593 template <typename ALLOC>
595 {
596  if (m_state != detail::CreatorState::IN_COMPOUND || m_valueStack.size() != 1)
597  {
598  throw CppRuntimeException("ZserioTreeCreator: Cannot end root in state '") << m_state << "'!";
599  }
600 
601  m_state = detail::CreatorState::BEFORE_ROOT;
602  auto value = m_valueStack.back();
603  m_valueStack.pop_back();
604  return value;
605 }
606 
607 template <typename ALLOC>
609 {
610  if (m_state != detail::CreatorState::IN_COMPOUND)
611  {
612  throw CppRuntimeException("ZserioTreeCreator: Cannot begin array in state '") << m_state << "'!";
613  }
614 
615  const auto& parentTypeInfo = getTypeInfo();
616  const auto& fieldInfo = findFieldInfo(parentTypeInfo, name);
617  if (!fieldInfo.isArray)
618  {
619  throw CppRuntimeException("ZserioTreeCreator: Member '")
620  << fieldInfo.schemaName << "' is not an array!";
621  }
622 
623  m_fieldInfoStack.push_back(fieldInfo);
624 
625  // note that we cannot just call getField() in case that the array is not optional like we do it in
626  // setValue() and beginCompound() methods because in case of arrays we would join multiple arrays together
627  // when this method is called multiple times with the same name - thus we will just create a new array
628  //
629  // moreover we need to properly initialize arrays of dynamic bit fields
630  // see https://github.com/ndsev/zserio/issues/414
631  m_valueStack.push_back(m_valueStack.back()->createField(name));
632 
633  m_state = detail::CreatorState::IN_ARRAY;
634 }
635 
636 template <typename ALLOC>
638 {
639  if (m_state != detail::CreatorState::IN_ARRAY)
640  {
641  throw CppRuntimeException("ZserioTreeCreator: Cannot end array in state '") << m_state << "'!";
642  }
643 
644  m_fieldInfoStack.pop_back();
645  m_valueStack.pop_back();
646  m_state = detail::CreatorState::IN_COMPOUND;
647 }
648 
649 template <typename ALLOC>
651 {
652  if (m_state != detail::CreatorState::IN_COMPOUND)
653  {
654  throw CppRuntimeException("ZserioTreeCreator: Cannot begin compound in state '") << m_state << "'!";
655  }
656 
657  const auto& parentTypeInfo = getTypeInfo();
658  const auto& fieldInfo = findFieldInfo(parentTypeInfo, name);
659  if (fieldInfo.isArray)
660  {
661  throw CppRuntimeException("ZserioTreeCreator: Member '") << fieldInfo.schemaName << "' is an array!";
662  }
663 
664  if (!TypeInfoUtil::isCompound(fieldInfo.typeInfo.getCppType()))
665  {
666  throw CppRuntimeException("ZserioTreeCreator: Member '")
667  << fieldInfo.schemaName << "' is not a compound!";
668  }
669 
670  m_fieldInfoStack.push_back(fieldInfo);
671  if (TypeInfoUtil::hasChoice(parentTypeInfo.getCppType()) || fieldInfo.isOptional)
672  {
673  // optional field, or field within choice or union -> create the new compound
674  m_valueStack.push_back(m_valueStack.back()->createField(name));
675  }
676  else
677  {
678  m_valueStack.push_back(m_valueStack.back()->getField(name));
679  }
680 
681  m_state = detail::CreatorState::IN_COMPOUND;
682 }
683 
684 template <typename ALLOC>
686 {
687  if (m_state != detail::CreatorState::IN_COMPOUND || m_fieldInfoStack.empty())
688  {
689  throw CppRuntimeException("ZserioTreeCreator: Cannot end compound in state '")
690  << m_state << "'" << (m_fieldInfoStack.empty() ? ", expecting endRoot!" : "!'");
691  }
692 
693  const BasicFieldInfo<ALLOC>& fieldInfo = m_fieldInfoStack.back();
694  if (fieldInfo.isArray)
695  {
696  throw CppRuntimeException("ZserioTreeCreator: Cannot end compound, it's an array element!");
697  }
698 
699  m_fieldInfoStack.pop_back();
700  m_valueStack.pop_back();
701 }
702 
703 template <typename ALLOC>
704 template <typename T>
706 {
707  if (m_state != detail::CreatorState::IN_COMPOUND)
708  {
709  throw CppRuntimeException("ZserioTreeCreator: Cannot set value in state '") << m_state << "'!";
710  }
711 
712  const BasicFieldInfo<ALLOC>& fieldInfo = findFieldInfo(getTypeInfo(), name);
713  if (fieldInfo.isArray)
714  {
715  throw CppRuntimeException("ZserioTreeCreator: Expecting array in member '")
716  << fieldInfo.schemaName << "'!";
717  }
718 
719  m_valueStack.back()->setField(
720  fieldInfo.schemaName, makeAnyValue(fieldInfo.typeInfo, std::forward<T>(value)));
721 }
722 
723 template <typename ALLOC>
724 void BasicZserioTreeCreator<ALLOC>::setValue(const string<ALLOC>& name, std::nullptr_t nullValue)
725 {
726  if (m_state != detail::CreatorState::IN_COMPOUND)
727  {
728  throw CppRuntimeException("ZserioTreeCreator: Cannot set value (null) in state '") << m_state << "'!";
729  }
730 
731  const BasicFieldInfo<ALLOC>& fieldInfo = findFieldInfo(getTypeInfo(), name);
732  if (fieldInfo.isOptional)
733  {
734  // reset an optional field
735  m_valueStack.back()->setField(fieldInfo.schemaName, AnyHolder<ALLOC>(nullValue, get_allocator()));
736  }
737  else
738  {
739  // reset non-optional field with default-constructed value
740  // (classes generated in C++ do not support null values)
741  m_valueStack.back()->createField(fieldInfo.schemaName);
742  }
743 }
744 
745 template <typename ALLOC>
747 {
748  if (m_state != detail::CreatorState::IN_COMPOUND)
749  {
750  throw CppRuntimeException("ZserioTreeCreator: Cannot get field type in state '") << m_state << "'!";
751  }
752 
753  return findFieldInfo(getTypeInfo(), name).typeInfo;
754 }
755 
756 template <typename ALLOC>
758 {
759  if (m_state != detail::CreatorState::IN_ARRAY)
760  {
761  throw CppRuntimeException("ZserioTreeCreator: Cannot begin compound element in state '")
762  << m_state << "'!";
763  }
764 
765  const BasicFieldInfo<ALLOC>& fieldInfo = m_fieldInfoStack.back();
766  if (!TypeInfoUtil::isCompound(fieldInfo.typeInfo.getCppType()))
767  {
768  throw CppRuntimeException("ZserioTreeCreator: Member '")
769  << fieldInfo.schemaName << "' is not a compound!";
770  }
771 
772  auto compoundArray = m_valueStack.back();
773  compoundArray->resize(compoundArray->size() + 1);
774  m_valueStack.push_back(compoundArray->at(compoundArray->size() - 1));
775  m_state = detail::CreatorState::IN_COMPOUND;
776 }
777 
778 template <typename ALLOC>
780 {
781  if (m_state != detail::CreatorState::IN_COMPOUND || m_fieldInfoStack.empty())
782  {
783  throw CppRuntimeException("ZserioTreeCreator: Cannot end compound element in state '")
784  << m_state << (m_fieldInfoStack.empty() ? ", expecting endRoot!" : "'!");
785  }
786 
787  const BasicFieldInfo<ALLOC>& fieldInfo = m_fieldInfoStack.back();
788  if (!fieldInfo.isArray)
789  {
790  throw CppRuntimeException("ZserioTreeCreator: Cannot end compound element, not in array!");
791  }
792 
793  m_valueStack.pop_back();
794  m_state = detail::CreatorState::IN_ARRAY;
795 }
796 
797 template <typename ALLOC>
798 template <typename T>
800 {
801  if (m_state != detail::CreatorState::IN_ARRAY)
802  {
803  throw CppRuntimeException("ZserioTreeCreator: Cannot add value element in state '") << m_state << "'!";
804  }
805 
806  const BasicFieldInfo<ALLOC>& fieldInfo = m_fieldInfoStack.back();
807  m_valueStack.back()->append(makeAnyValue(fieldInfo.typeInfo, std::forward<T>(value)));
808 }
809 
810 template <typename ALLOC>
812 {
813  if (m_state != detail::CreatorState::IN_ARRAY)
814  {
815  throw CppRuntimeException("ZserioTreeCreator: Cannot get element type in state '") << m_state << "'!";
816  }
817 
818  return m_fieldInfoStack.back().get().typeInfo;
819 }
820 
821 template <typename ALLOC>
823 {
824  return m_fieldInfoStack.empty() ? m_typeInfo : m_fieldInfoStack.back().get().typeInfo;
825 }
826 
827 template <typename ALLOC>
828 const BasicFieldInfo<ALLOC>& BasicZserioTreeCreator<ALLOC>::findFieldInfo(
829  const IBasicTypeInfo<ALLOC>& typeInfo, StringView name) const
830 {
831  Span<const BasicFieldInfo<ALLOC>> fields = typeInfo.getFields();
832  auto found_it = std::find_if(fields.begin(), fields.end(), [name](const BasicFieldInfo<ALLOC>& field) {
833  return field.schemaName == name;
834  });
835  if (found_it == fields.end())
836  {
837  throw CppRuntimeException("ZserioTreeCreator: Member '")
838  << name << "' not found in '" << typeInfo.getSchemaName() << "'!";
839  }
840 
841  return *found_it;
842 }
843 
844 template <typename ALLOC>
845 template <typename T>
846 AnyHolder<ALLOC> BasicZserioTreeCreator<ALLOC>::makeAnyValue(
847  const IBasicTypeInfo<ALLOC>& typeInfo, T&& value) const
848 {
849  return detail::makeAnyValue(typeInfo, std::forward<T>(value), get_allocator());
850 }
851 
852 } // namespace zserio
853 
854 #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:454
string< ALLOC > toString(T value, const ALLOC &allocator=ALLOC())
typename IBasicReflectable< ALLOC >::Ptr IBasicReflectablePtr
Definition: IReflectable.h:532
StringView schemaName
Definition: ITypeInfo.h:380
const IBasicTypeInfo< ALLOC > & typeInfo
Definition: ITypeInfo.h:381
static bool hasChoice(SchemaType schemaType)
static bool isCompound(SchemaType schemaType)
Definition: TypeInfoUtil.cpp:6
static bool isSigned(SchemaType schemaType)