Zserio C++17 runtime library 1.3.0
Built for Zserio 2.20.0
Loading...
Searching...
No Matches
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
21namespace zserio
22{
23
24namespace detail
25{
26
27template <typename T, typename ALLOC>
28BasicAny<ALLOC> makeAnyValue(const IBasicTypeInfo<ALLOC>& typeInfo, T&& value, const ALLOC& allocator);
29
30template <typename T, typename U, std::enable_if_t<std::is_integral_v<std::decay_t<U>>, int> = 0>
31bool 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
52template <typename T, typename U, std::enable_if_t<is_numeric_wrapper_v<std::decay_t<U>>, int> = 0>
53bool checkArithmeticValueRanges(U value)
54{
55 return checkArithmeticValueRanges<T>(static_cast<typename U::ValueType>(value));
56}
57
58template <typename T, typename ALLOC>
59BasicAny<ALLOC> makeAnyBoolValue(bool value, const ALLOC& allocator)
60{
61 return BasicAny<ALLOC>(static_cast<T>(value), allocator);
62}
63
64template <typename T, typename U, typename ALLOC>
65BasicAny<ALLOC> makeAnyBoolValue(const U& value, const ALLOC&)
66{
67 throw CppRuntimeException("ZserioTreeCreator: Value '") << value << "' cannot be converted to bool value!";
68}
69
70template <typename T, typename ALLOC>
71BasicAny<ALLOC> makeAnyIntegralValue(bool value, const ALLOC&)
72{
73 throw CppRuntimeException("ZserioTreeCreator: Bool value '")
74 << value << "' cannot be converted to integral type!";
75}
76
77template <typename T, typename U, typename ALLOC>
78BasicAny<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
100template <typename T, typename ALLOC>
101BasicAny<ALLOC> makeAnyFloatingValue(bool value, const ALLOC&)
102{
103 throw CppRuntimeException("ZserioTreeCreator: Bool value '")
104 << value << "' cannot be converted to floating type!";
105}
106
107template <typename T, typename U, typename ALLOC>
108BasicAny<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
123template <typename ALLOC>
124BasicAny<ALLOC> makeAnyStringValue(const BasicString<RebindAlloc<ALLOC, char>>& value, const ALLOC& allocator)
125{
126 return BasicAny<ALLOC>(value, allocator);
127}
128
129template <typename ALLOC>
130BasicAny<ALLOC> makeAnyStringValue(BasicString<RebindAlloc<ALLOC, char>>&& value, const ALLOC& allocator)
131{
132 return BasicAny<ALLOC>(std::move(value), allocator);
133}
134
135template <typename ALLOC>
136BasicAny<ALLOC> makeAnyStringValue(std::string_view value, const ALLOC& allocator)
137{
138 return BasicAny<ALLOC>(toString(value, allocator), allocator);
139}
140
141template <typename ALLOC>
142BasicAny<ALLOC> makeAnyStringValue(const char* value, const ALLOC& allocator)
143{
144 return makeAnyStringValue(std::string_view(value), allocator);
145}
146
147template <typename T, typename ALLOC>
148BasicAny<ALLOC> makeAnyStringValue(const T&, const ALLOC&)
149{
150 throw CppRuntimeException("ZserioTreeCreator: Trying to make any string value from unsupported type!");
151}
152
153template <typename ALLOC>
154BasicAny<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 {
161 if (TypeInfoUtil::isSigned(typeInfo.getUnderlyingType().getCppType()))
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
176template <typename ALLOC>
177BasicAny<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
199template <typename ALLOC>
200BasicAny<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
206template <typename ALLOC>
207BasicAny<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
213template <typename T, typename ALLOC, typename std::enable_if<std::is_enum<T>::value, int>::type = 0>
214BasicAny<ALLOC> makeAnyEnumValue(T enumValue, const IBasicTypeInfo<ALLOC>&, const ALLOC& allocator)
215{
216 return BasicAny<ALLOC>(enumValue, allocator);
217}
218
219template <typename T, typename ALLOC, typename std::enable_if<!std::is_enum<T>::value, int>::type = 0>
220BasicAny<ALLOC> makeAnyEnumValue(T enumRawValue, const IBasicTypeInfo<ALLOC>& typeInfo, const ALLOC& allocator)
221{
222 return makeAnyValue(typeInfo.getUnderlyingType(), enumRawValue, allocator);
223}
224
225template <typename ALLOC>
226BasicAny<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
281template <typename ALLOC>
282BasicAny<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
295template <typename ALLOC>
296BasicAny<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
328template <typename ALLOC>
329BasicAny<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
335template <typename ALLOC>
336BasicAny<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
342template <typename T, typename ALLOC, typename std::enable_if<is_bitmask<T>::value, int>::type = 0>
343BasicAny<ALLOC> makeAnyBitmaskValue(T bitmaskValue, const IBasicTypeInfo<ALLOC>&, const ALLOC& allocator)
344{
345 return BasicAny<ALLOC>(bitmaskValue, allocator);
346}
347
348template <typename T, typename ALLOC, typename std::enable_if<!is_bitmask<T>::value, int>::type = 0>
349BasicAny<ALLOC> makeAnyBitmaskValue(
350 T bitmaskRawValue, const IBasicTypeInfo<ALLOC>& typeInfo, const ALLOC& allocator)
351{
352 return makeAnyValue(typeInfo.getUnderlyingType(), bitmaskRawValue, allocator);
353}
354
355template <typename T, typename ALLOC>
356BasicAny<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
394template <typename ALLOC>
395BasicAny<ALLOC> makeAnyValue(const IBasicTypeInfo<ALLOC>&, BasicAny<ALLOC>&& anyValue, const ALLOC&)
396{
397 return std::move(anyValue);
398}
399
400enum class CreatorState : uint8_t
401{
402 BEFORE_ROOT,
403 IN_COMPOUND,
404 IN_ARRAY
405};
406
407} // namespace detail
408
417CppRuntimeException& operator<<(CppRuntimeException& exception, detail::CreatorState state);
418
422template <typename ALLOC>
424{
425public:
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
519
525 void endCompoundElement();
526
534 template <typename T>
535 void addValueElement(T&& value);
536
545
546private:
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
567template <typename ALLOC>
571 m_typeInfo(typeInfo),
572 m_fieldInfoStack(allocator),
573 m_valueStack(allocator)
574{}
575
576template <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
588template <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
602template <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
631template <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
644template <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
679template <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
698template <typename ALLOC>
699template <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
718template <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
741template <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
753template <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
775template <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
794template <typename ALLOC>
795template <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
807template <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
818template <typename ALLOC>
820{
821 return m_fieldInfoStack.empty() ? m_typeInfo : m_fieldInfoStack.back().get().typeInfo;
822}
823
824template <typename ALLOC>
825const 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
841template <typename ALLOC>
842template <typename T>
843BasicAny<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
allocator_type get_allocator() const
const IBasicTypeInfo< ALLOC > & getElementType() const
void setValue(const BasicString< RebindAlloc< ALLOC, char > > &name, T &&value)
BasicZserioTreeCreator(const IBasicTypeInfo< ALLOC > &typeInfo, const ALLOC &allocator=ALLOC())
void beginCompound(const BasicString< RebindAlloc< ALLOC, char > > &name)
const IBasicTypeInfo< ALLOC > & getFieldType(const BasicString< RebindAlloc< ALLOC, char > > &name) const
IBasicReflectableDataPtr< ALLOC > endRoot()
void beginArray(const BasicString< RebindAlloc< ALLOC, char > > &name)
const IBasicTypeInfo< ALLOC > & typeInfo()
Definition ITypeInfo.h:668
std::basic_string< char, std::char_traits< char >, ALLOC > BasicString
Definition String.h:17
CppRuntimeException & operator<<(CppRuntimeException &exception, const BasicBitBuffer< ALLOC > &bitBuffer)
Definition BitBuffer.h:554
BasicString< RebindAlloc< ALLOC, char > > toString(T value, const ALLOC &allocator=ALLOC())
static bool hasChoice(SchemaType schemaType)
static bool isCompound(SchemaType schemaType)
static bool isSigned(SchemaType schemaType)