1#ifndef ZSERIO_ZSERIO_TREE_CREATOR_H_INC
2#define ZSERIO_ZSERIO_TREE_CREATOR_H_INC
27template <
typename T,
typename ALLOC>
28BasicAny<ALLOC> makeAnyValue(
const IBasicTypeInfo<ALLOC>&
typeInfo, T&& value,
const ALLOC& allocator);
30template <
typename T,
typename U, std::enable_if_t<std::is_
integral_v<std::decay_t<U>>,
int> = 0>
31bool checkArithmeticValueRanges(U value)
33 if constexpr (std::is_unsigned_v<std::decay_t<U>>)
36 return (value <=
static_cast<U
>(std::numeric_limits<T>::max()));
38 else if constexpr (std::is_signed_v<std::decay_t<U>> && std::is_signed_v<std::decay_t<T>>)
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()));
44 else if constexpr (std::is_signed_v<std::decay_t<U>> && std::is_unsigned_v<std::decay_t<T>>)
48 static_cast<uint64_t
>(value) <=
static_cast<uint64_t
>(std::numeric_limits<T>::max()));
52template <
typename T,
typename U, std::enable_if_t<is_numeric_wrapper_v<std::decay_t<U>>,
int> = 0>
53bool checkArithmeticValueRanges(U value)
55 return checkArithmeticValueRanges<T>(
static_cast<typename U::ValueType
>(value));
58template <
typename T,
typename ALLOC>
59BasicAny<ALLOC> makeAnyBoolValue(
bool value,
const ALLOC& allocator)
61 return BasicAny<ALLOC>(
static_cast<T
>(value), allocator);
64template <
typename T,
typename U,
typename ALLOC>
65BasicAny<ALLOC> makeAnyBoolValue(
const U& value,
const ALLOC&)
67 throw CppRuntimeException(
"ZserioTreeCreator: Value '") << value <<
"' cannot be converted to bool value!";
70template <
typename T,
typename ALLOC>
71BasicAny<ALLOC> makeAnyIntegralValue(
bool value,
const ALLOC&)
73 throw CppRuntimeException(
"ZserioTreeCreator: Bool value '")
74 << value <<
"' cannot be converted to integral type!";
77template <
typename T,
typename U,
typename ALLOC>
78BasicAny<ALLOC> makeAnyIntegralValue(U value,
const ALLOC& allocator)
80 using Type = std::decay_t<U>;
81 if constexpr (std::is_integral_v<Type> || is_numeric_wrapper_v<Type>)
84 if (!checkArithmeticValueRanges<T>(value))
86 throw CppRuntimeException(
"ZserioTreeCreator: Integral value '")
87 << value <<
"' overflow (<" << std::numeric_limits<T>::min() <<
", "
88 << std::numeric_limits<T>::max() <<
">)!";
91 return BasicAny<ALLOC>(
static_cast<T
>(value), allocator);
95 throw CppRuntimeException(
"ZserioTreeCreator: Value '")
96 << value <<
"' cannot be converted to integral value!";
100template <
typename T,
typename ALLOC>
101BasicAny<ALLOC> makeAnyFloatingValue(
bool value,
const ALLOC&)
103 throw CppRuntimeException(
"ZserioTreeCreator: Bool value '")
104 << value <<
"' cannot be converted to floating type!";
107template <
typename T,
typename U,
typename ALLOC>
108BasicAny<ALLOC> makeAnyFloatingValue(U value,
const ALLOC& allocator)
110 using Type = std::decay_t<U>;
111 if constexpr (std::is_arithmetic_v<Type> || is_numeric_wrapper_v<Type>)
114 return BasicAny<ALLOC>(
static_cast<T
>(value), allocator);
118 throw CppRuntimeException(
"ZserioTreeCreator: Value '")
119 << value <<
"' cannot be converted to floating value!";
123template <
typename ALLOC>
124BasicAny<ALLOC> makeAnyStringValue(
const BasicString<RebindAlloc<ALLOC, char>>& value,
const ALLOC& allocator)
126 return BasicAny<ALLOC>(value, allocator);
129template <
typename ALLOC>
130BasicAny<ALLOC> makeAnyStringValue(
BasicString<RebindAlloc<ALLOC, char>>&& value,
const ALLOC& allocator)
132 return BasicAny<ALLOC>(std::move(value), allocator);
135template <
typename ALLOC>
136BasicAny<ALLOC> makeAnyStringValue(std::string_view value,
const ALLOC& allocator)
138 return BasicAny<ALLOC>(
toString(value, allocator), allocator);
141template <
typename ALLOC>
142BasicAny<ALLOC> makeAnyStringValue(
const char* value,
const ALLOC& allocator)
144 return makeAnyStringValue(std::string_view(value), allocator);
147template <
typename T,
typename ALLOC>
148BasicAny<ALLOC> makeAnyStringValue(
const T&,
const ALLOC&)
150 throw CppRuntimeException(
"ZserioTreeCreator: Trying to make any string value from unsupported type!");
153template <
typename ALLOC>
154BasicAny<ALLOC> parseEnumStringValue(
155 std::string_view stringValue,
const IBasicTypeInfo<ALLOC>&
typeInfo,
const ALLOC& allocator)
157 for (
const auto& itemInfo :
typeInfo.getEnumItems())
159 if (itemInfo.schemaName == stringValue)
164 typeInfo.getUnderlyingType(),
static_cast<int64_t
>(itemInfo.value), allocator);
168 return makeAnyValue(
typeInfo.getUnderlyingType(), itemInfo.value, allocator);
173 return BasicAny<ALLOC>(allocator);
176template <
typename ALLOC>
177BasicAny<ALLOC> makeAnyEnumValue(
178 std::string_view stringValue,
const IBasicTypeInfo<ALLOC>&
typeInfo,
const ALLOC& allocator)
180 if (!stringValue.empty())
182 const char firstChar = stringValue[0];
183 if ((firstChar >=
'A' && firstChar <=
'Z') || (firstChar >=
'a' && firstChar <=
'z') ||
186 BasicAny<ALLOC> anyValue = parseEnumStringValue(stringValue,
typeInfo, allocator);
187 if (anyValue.hasValue())
195 throw CppRuntimeException(
"ZserioTreeCreator: Cannot create enum '")
196 <<
typeInfo.getSchemaName() <<
"' from string value '" << stringValue <<
"'!";
199template <
typename ALLOC>
200BasicAny<ALLOC> makeAnyEnumValue(
const BasicString<RebindAlloc<ALLOC, char>>& stringValue,
201 const IBasicTypeInfo<ALLOC>&
typeInfo,
const ALLOC& allocator)
203 return makeAnyEnumValue(std::string_view(stringValue),
typeInfo, allocator);
206template <
typename ALLOC>
207BasicAny<ALLOC> makeAnyEnumValue(
208 const char* stringValue,
const IBasicTypeInfo<ALLOC>&
typeInfo,
const ALLOC& allocator)
210 return makeAnyEnumValue(std::string_view(stringValue),
typeInfo, allocator);
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)
216 return BasicAny<ALLOC>(enumValue, allocator);
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)
222 return makeAnyValue(
typeInfo.getUnderlyingType(), enumRawValue, allocator);
225template <
typename ALLOC>
226BasicAny<ALLOC> parseBitmaskStringValue(
227 std::string_view stringValue,
const IBasicTypeInfo<ALLOC>&
typeInfo,
const ALLOC& allocator)
231 while (pos < stringValue.size())
234 const size_t available = stringValue.size() - pos;
235 for (
const auto& itemInfo :
typeInfo.getBitmaskValues())
237 if (available >= itemInfo.schemaName.size() &&
238 stringValue.substr(pos, itemInfo.schemaName.size()) == itemInfo.schemaName)
240 const size_t newPos = pos + itemInfo.schemaName.size();
242 if (newPos == stringValue.size() || stringValue[newPos] ==
' ' || stringValue[newPos] ==
'|')
244 value |= itemInfo.value;
245 if (newPos == stringValue.size())
247 return makeAnyValue(
typeInfo.getUnderlyingType(), value, allocator);
250 pos += itemInfo.schemaName.size();
261 while (pos < stringValue.size() && stringValue[pos] ==
' ')
266 if (pos < stringValue.size() && stringValue[pos] ==
'|')
271 while (pos < stringValue.size() && stringValue[pos] ==
' ')
278 return BasicAny<ALLOC>(allocator);
281template <
typename ALLOC>
282BasicAny<ALLOC> parseBitmaskNumericStringValue(
283 const char* stringValue,
const IBasicTypeInfo<ALLOC>&
typeInfo,
const ALLOC& allocator)
285 char* pEnd =
nullptr;
287 uint64_t value = std::strtoull(stringValue, &pEnd, 10);
290 return BasicAny<ALLOC>(allocator);
292 return makeAnyValue(
typeInfo.getUnderlyingType(), value, allocator);
295template <
typename ALLOC>
296BasicAny<ALLOC> makeAnyBitmaskValue(
297 std::string_view stringValue,
const IBasicTypeInfo<ALLOC>&
typeInfo,
const ALLOC& allocator)
299 if (!stringValue.empty())
301 const char firstChar = stringValue[0];
302 if ((firstChar >=
'A' && firstChar <=
'Z') || (firstChar >=
'a' && firstChar <=
'z') ||
305 BasicAny<ALLOC> anyValue = parseBitmaskStringValue(stringValue,
typeInfo, allocator);
306 if (anyValue.hasValue())
311 else if (firstChar >=
'0' && firstChar <=
'9')
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())
324 throw CppRuntimeException(
"ZserioTreeCreator: Cannot create bitmask '")
325 <<
typeInfo.getSchemaName() <<
"' from string value '" << stringValue <<
"'!";
328template <
typename ALLOC>
329BasicAny<ALLOC> makeAnyBitmaskValue(
const BasicString<RebindAlloc<ALLOC, char>>& stringValue,
330 const IBasicTypeInfo<ALLOC>&
typeInfo,
const ALLOC& allocator)
332 return makeAnyBitmaskValue(std::string_view(stringValue),
typeInfo, allocator);
335template <
typename ALLOC>
336BasicAny<ALLOC> makeAnyBitmaskValue(
337 const char* stringValue,
const IBasicTypeInfo<ALLOC>&
typeInfo,
const ALLOC& allocator)
339 return makeAnyBitmaskValue(std::string_view(stringValue),
typeInfo, allocator);
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)
345 return BasicAny<ALLOC>(bitmaskValue, allocator);
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)
352 return makeAnyValue(
typeInfo.getUnderlyingType(), bitmaskRawValue, allocator);
355template <
typename T,
typename ALLOC>
356BasicAny<ALLOC> makeAnyValue(
const IBasicTypeInfo<ALLOC>&
typeInfo, T&& value,
const ALLOC& allocator)
361 return makeAnyBoolValue<bool>(std::forward<T>(value), allocator);
363 return makeAnyIntegralValue<uint8_t>(std::forward<T>(value), allocator);
365 return makeAnyIntegralValue<uint16_t>(std::forward<T>(value), allocator);
367 return makeAnyIntegralValue<uint32_t>(std::forward<T>(value), allocator);
369 return makeAnyIntegralValue<uint64_t>(std::forward<T>(value), allocator);
371 return makeAnyIntegralValue<int8_t>(std::forward<T>(value), allocator);
373 return makeAnyIntegralValue<int16_t>(std::forward<T>(value), allocator);
375 return makeAnyIntegralValue<int32_t>(std::forward<T>(value), allocator);
377 return makeAnyIntegralValue<int64_t>(std::forward<T>(value), allocator);
379 return makeAnyFloatingValue<float>(std::forward<T>(value), allocator);
381 return makeAnyFloatingValue<double>(std::forward<T>(value), allocator);
383 return makeAnyStringValue(std::forward<T>(value), allocator);
385 return makeAnyEnumValue(std::forward<T>(value),
typeInfo, allocator);
387 return makeAnyBitmaskValue(std::forward<T>(value),
typeInfo, allocator);
389 return BasicAny<ALLOC>(std::forward<T>(value), allocator);
394template <
typename ALLOC>
395BasicAny<ALLOC> makeAnyValue(
const IBasicTypeInfo<ALLOC>&, BasicAny<ALLOC>&& anyValue,
const ALLOC&)
397 return std::move(anyValue);
400enum class CreatorState : uint8_t
417CppRuntimeException&
operator<<(CppRuntimeException& exception, detail::CreatorState state);
422template <
typename ALLOC>
487 template <
typename T>
534 template <
typename T>
549 using BasicFieldInfoRef = std::reference_wrapper<const BasicFieldInfo<ALLOC>>;
555 template <
typename T>
561 detail::CreatorState m_state = detail::CreatorState::BEFORE_ROOT;
567template <
typename ALLOC>
576template <
typename ALLOC>
579 if (m_state != detail::CreatorState::BEFORE_ROOT)
581 throw CppRuntimeException(
"ZserioTreeCreator: Cannot begin root in state '") << m_state <<
"'!";
584 m_valueStack.push_back(m_typeInfo.createInstance(get_allocator()));
585 m_state = detail::CreatorState::IN_COMPOUND;
588template <
typename ALLOC>
591 if (m_state != detail::CreatorState::IN_COMPOUND || m_valueStack.size() != 1)
593 throw CppRuntimeException(
"ZserioTreeCreator: Cannot end root in state '") << m_state <<
"'!";
596 m_state = detail::CreatorState::BEFORE_ROOT;
597 auto value = m_valueStack.back();
598 m_valueStack.pop_back();
602template <
typename ALLOC>
605 if (m_state != detail::CreatorState::IN_COMPOUND)
607 throw CppRuntimeException(
"ZserioTreeCreator: Cannot begin array in state '") << m_state <<
"'!";
615 <<
fieldInfo.schemaName <<
"' is not an array!";
626 m_valueStack.push_back(m_valueStack.back()->createField(name));
628 m_state = detail::CreatorState::IN_ARRAY;
631template <
typename ALLOC>
634 if (m_state != detail::CreatorState::IN_ARRAY)
636 throw CppRuntimeException(
"ZserioTreeCreator: Cannot end array in state '") << m_state <<
"'!";
639 m_fieldInfoStack.pop_back();
640 m_valueStack.pop_back();
641 m_state = detail::CreatorState::IN_COMPOUND;
644template <
typename ALLOC>
647 if (m_state != detail::CreatorState::IN_COMPOUND)
649 throw CppRuntimeException(
"ZserioTreeCreator: Cannot begin compound in state '") << m_state <<
"'!";
662 <<
fieldInfo.schemaName <<
"' is not a compound!";
669 m_valueStack.push_back(m_valueStack.back()->createField(name));
673 m_valueStack.push_back(m_valueStack.back()->getField(name));
676 m_state = detail::CreatorState::IN_COMPOUND;
679template <
typename ALLOC>
682 if (m_state != detail::CreatorState::IN_COMPOUND || m_fieldInfoStack.empty())
685 << m_state <<
"'" << (m_fieldInfoStack.empty() ?
", expecting endRoot!" :
"!'");
691 throw CppRuntimeException(
"ZserioTreeCreator: Cannot end compound, it's an array element!");
694 m_fieldInfoStack.pop_back();
695 m_valueStack.pop_back();
698template <
typename ALLOC>
702 if (m_state != detail::CreatorState::IN_COMPOUND)
704 throw CppRuntimeException(
"ZserioTreeCreator: Cannot set value in state '") << m_state <<
"'!";
714 m_valueStack.back()->setField(
718template <
typename ALLOC>
722 if (m_state != detail::CreatorState::IN_COMPOUND)
724 throw CppRuntimeException(
"ZserioTreeCreator: Cannot set value (null) in state '") << m_state <<
"'!";
737 m_valueStack.back()->createField(
fieldInfo.schemaName);
741template <
typename ALLOC>
745 if (m_state != detail::CreatorState::IN_COMPOUND)
747 throw CppRuntimeException(
"ZserioTreeCreator: Cannot get field type in state '") << m_state <<
"'!";
750 return findFieldInfo(getTypeInfo(), name).typeInfo;
753template <
typename ALLOC>
756 if (m_state != detail::CreatorState::IN_ARRAY)
766 <<
fieldInfo.schemaName <<
"' is not a compound!";
772 m_state = detail::CreatorState::IN_COMPOUND;
775template <
typename ALLOC>
778 if (m_state != detail::CreatorState::IN_COMPOUND || m_fieldInfoStack.empty())
781 << m_state << (m_fieldInfoStack.empty() ?
", expecting endRoot!" :
"'!");
787 throw CppRuntimeException(
"ZserioTreeCreator: Cannot end compound element, not in array!");
790 m_valueStack.pop_back();
791 m_state = detail::CreatorState::IN_ARRAY;
794template <
typename ALLOC>
798 if (m_state != detail::CreatorState::IN_ARRAY)
800 throw CppRuntimeException(
"ZserioTreeCreator: Cannot add value element in state '") << m_state <<
"'!";
804 m_valueStack.back()->append(makeAnyValue(
fieldInfo.typeInfo, std::forward<T>(value)));
807template <
typename ALLOC>
810 if (m_state != detail::CreatorState::IN_ARRAY)
812 throw CppRuntimeException(
"ZserioTreeCreator: Cannot get element type in state '") << m_state <<
"'!";
815 return m_fieldInfoStack.back().get().typeInfo;
818template <
typename ALLOC>
821 return m_fieldInfoStack.empty() ? m_typeInfo : m_fieldInfoStack.back().get().typeInfo;
824template <
typename ALLOC>
825const BasicFieldInfo<ALLOC>& BasicZserioTreeCreator<ALLOC>::findFieldInfo(
826 const IBasicTypeInfo<ALLOC>&
typeInfo, std::string_view name)
const
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;
832 if (found_it == fields.end())
834 throw CppRuntimeException(
"ZserioTreeCreator: Member '")
835 << name <<
"' not found in '" <<
typeInfo.getSchemaName() <<
"'!";
841template <
typename ALLOC>
843BasicAny<ALLOC> BasicZserioTreeCreator<ALLOC>::makeAnyValue(
844 const IBasicTypeInfo<ALLOC>&
typeInfo, T&& value)
const
846 return detail::makeAnyValue(
typeInfo, std::forward<T>(value), get_allocator());
allocator_type get_allocator() const
const IBasicTypeInfo< ALLOC > & getElementType() const
void setValue(const BasicString< RebindAlloc< ALLOC, char > > &name, T &&value)
void beginCompoundElement()
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
void addValueElement(T &&value)
void endCompoundElement()
IBasicReflectableDataPtr< ALLOC > endRoot()
void beginArray(const BasicString< RebindAlloc< ALLOC, char > > &name)
const IBasicTypeInfo< ALLOC > & typeInfo()
std::basic_string< char, std::char_traits< char >, ALLOC > BasicString
CppRuntimeException & operator<<(CppRuntimeException &exception, const BasicBitBuffer< ALLOC > &bitBuffer)
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)