38template <VariantPolicy>
52 template <VariantPolicy Policy = VariantPolicy::Copy,
typename T>
61 template <VariantPolicy Policy = VariantPolicy::Copy,
typename T>
70 template <VariantPolicy Policy = VariantPolicy::Copy,
typename ArrayLike>
75 Handler::setArray(var,
Span{std::forward<ArrayLike>(array)});
77 Handler::setArray(var, array.begin(), array.end());
84 template <VariantPolicy Policy = VariantPolicy::Copy,
typename ArrayLike>
89 Handler::setArray(var,
Span{std::forward<ArrayLike>(array)}, dataType);
91 Handler::setArray(var, array.begin(), array.end(), dataType);
98 template <VariantPolicy Policy = VariantPolicy::Copy,
typename InputIt>
107 template <VariantPolicy Policy = VariantPolicy::Copy,
typename InputIt>
109 InputIt first, InputIt last,
const UA_DataType& dataType
118 return handle()->type ==
nullptr;
137 handle()->type !=
nullptr && dataType !=
nullptr &&
138 handle()->type->typeId == dataType->typeId
149 [[deprecated(
"Use isType<T>() instead, the Type enum will be removed")]]
156 return (
handle()->type !=
nullptr) && (
handle()->type->typeId == id);
160 template <
typename T>
162 return isType(opcua::getDataType<T>());
172 [[deprecated(
"Use getDataType() or isType<T>() instead, the Type enum will be removed")]]
174 if (
handle()->type !=
nullptr) {
175 const auto typeIndex =
handle()->type->typeKind;
177 return static_cast<Type>(typeIndex);
191 const void*
data() const noexcept {
196 [[deprecated(
"Use the methods isScalar() and data() instead")]]
203 [[deprecated(
"Use the methods isScalar() and data() instead")]]
211 template <
typename T>
215 checkIsDataType<T>();
216 return *
static_cast<T*
>(
handle()->data);
220 template <
typename T>
224 checkIsDataType<T>();
225 return *
static_cast<const T*
>(
handle()->data);
229 template <
typename T>
231 return std::move(getScalar<T>());
235 template <
typename T>
237 return std::move(getScalar<T>());
242 template <
typename T>
244 assertIsCopyableOrConvertible<T>();
245 return getScalarCopyImpl<T>();
250 return handle()->arrayLength;
255 return {
handle()->arrayDimensions,
handle()->arrayDimensionsSize};
259 [[deprecated(
"Use the methods isArray() and data() instead")]]
266 [[deprecated(
"Use the methods isArray() and data() instead")]]
274 template <
typename T>
278 checkIsDataType<T>();
284 template <
typename T>
288 checkIsDataType<T>();
294 template <
typename T>
296 assertIsCopyableOrConvertible<T>();
297 return getArrayCopyImpl<T>();
301 template <
typename T>
304 setScalar(value, opcua::getDataType<T>());
308 template <
typename T>
314 template <
typename T>
316 assertIsCopyableOrConvertible<T>();
317 if constexpr (detail::isRegisteredType<T>) {
318 setScalarCopyImpl(value, opcua::getDataType<T>());
320 setScalarCopyConvertImpl(value);
325 template <
typename T>
327 setScalarCopyImpl(value, dataType);
336 template <
typename ArrayLike>
338 using ValueType =
typename std::remove_reference_t<ArrayLike>::value_type;
339 assertIsNative<ValueType>();
340 setArray(std::forward<ArrayLike>(array), opcua::getDataType<ValueType>());
348 template <
typename ArrayLike>
350 static_assert(!isTemporaryArray<decltype(array)>());
359 template <
typename ArrayLike>
369 template <
typename ArrayLike>
377 template <
typename InputIt>
379 using ValueType =
typename std::iterator_traits<InputIt>::value_type;
380 assertIsCopyableOrConvertible<ValueType>();
381 if constexpr (detail::isRegisteredType<ValueType>) {
382 setArrayCopyImpl(first, last, opcua::getDataType<ValueType>());
384 setArrayCopyConvertImpl(first, last);
391 template <
typename InputIt>
393 setArrayCopyImpl(first, last, dataType);
397 template <
typename ArrayLike>
398 static constexpr bool isTemporaryArray() {
399 constexpr bool isTemporary = std::is_rvalue_reference_v<ArrayLike>;
401 return isTemporary && !isView;
404 template <
typename T>
405 static constexpr void assertIsNative() {
407 detail::isRegisteredType<T>,
408 "Template type must be a native/wrapper type to assign or get scalar/array without copy"
412 template <
typename T>
413 static constexpr void assertIsCopyableOrConvertible() {
415 detail::isRegisteredType<T> || detail::isConvertibleType<T>,
416 "Template type must be either a native/wrapper type (copyable) or a convertible type. "
417 "If the type is a native type: Provide the data type (UA_DataType) manually "
418 "or register the type with a TypeRegistry template specialization. "
419 "If the type should be converted: Add a template specialization for TypeConverter."
423 template <
typename T>
424 static constexpr void assertNoVariant() {
426 !std::is_same_v<T, Variant> && !std::is_same_v<T, UA_Variant>,
427 "Variants cannot directly contain another variant"
431 void checkIsScalar()
const {
433 throw BadVariantAccess(
"Variant is not a scalar");
437 void checkIsArray()
const {
439 throw BadVariantAccess(
"Variant is not an array");
443 template <
typename T>
444 void checkIsDataType()
const {
446 if (dt ==
nullptr || dt->typeId != opcua::getDataType<T>().typeId) {
447 throw BadVariantAccess(
"Variant does not contain a value convertible to template type");
451 template <
typename T>
452 inline T getScalarCopyImpl()
const;
453 template <
typename T>
454 inline std::vector<T> getArrayCopyImpl()
const;
456 template <
typename T>
457 inline void setScalarImpl(
460 template <
typename T>
461 inline void setArrayImpl(
464 template <
typename T>
465 inline void setScalarCopyImpl(
const T& value,
const UA_DataType& dataType);
466 template <
typename T>
467 inline void setScalarCopyConvertImpl(
const T& value);
468 template <
typename InputIt>
469 inline void setArrayCopyImpl(InputIt first, InputIt last,
const UA_DataType& dataType);
470 template <
typename InputIt>
471 inline void setArrayCopyConvertImpl(InputIt first, InputIt last);
477T Variant::getScalarCopyImpl()
const {
478 if constexpr (detail::isRegisteredType<T>) {
479 return detail::copy(getScalar<T>(), opcua::getDataType<T>());
481 using Native =
typename TypeConverter<T>::NativeType;
483 TypeConverter<T>::fromNative(getScalar<Native>(), result);
489std::vector<T> Variant::getArrayCopyImpl()
const {
490 std::vector<T> result(
handle()->arrayLength);
491 if constexpr (detail::isRegisteredType<T>) {
492 auto native = getArray<T>();
493 std::transform(
native.begin(),
native.end(), result.begin(), [](
auto&& value) {
494 return detail::copy(value, opcua::getDataType<T>());
497 using Native =
typename TypeConverter<T>::NativeType;
498 auto native = getArray<Native>();
499 for (
size_t i = 0; i <
native.size(); ++i) {
500 TypeConverter<T>::fromNative(
native[i], result[i]);
507void Variant::setScalarImpl(
510 assertNoVariant<T>();
511 assert(
sizeof(T) == dataType.memSize);
513 handle()->type = &dataType;
514 handle()->storageType = storageType;
515 handle()->data = data;
519void Variant::setArrayImpl(
522 assertNoVariant<T>();
523 assert(
sizeof(T) == dataType.memSize);
525 handle()->type = &dataType;
526 handle()->storageType = storageType;
527 handle()->data = data;
528 handle()->arrayLength = arrayLength;
532void Variant::setScalarCopyImpl(
const T& value,
const UA_DataType& dataType) {
533 auto native = detail::allocateUniquePtr<T>(dataType);
535 setScalarImpl(
native.release(), dataType, UA_VARIANT_DATA);
539void Variant::setScalarCopyConvertImpl(
const T& value) {
540 using Native =
typename TypeConverter<T>::NativeType;
541 const auto& dataType = opcua::getDataType<Native>();
542 auto native = detail::allocateUniquePtr<Native>(dataType);
543 TypeConverter<T>::toNative(value, *
native);
544 setScalarImpl(
native.release(), dataType, UA_VARIANT_DATA);
547template <
typename InputIt>
548void Variant::setArrayCopyImpl(InputIt first, InputIt last,
const UA_DataType& dataType) {
549 using ValueType =
typename std::iterator_traits<InputIt>::value_type;
550 const size_t size = std::distance(first, last);
551 auto native = detail::allocateArrayUniquePtr<ValueType>(size, dataType);
552 std::transform(first, last,
native.get(), [&](
const ValueType& value) {
553 return detail::copy(value, dataType);
555 setArrayImpl(
native.release(), size, dataType, UA_VARIANT_DATA);
558template <
typename InputIt>
559void Variant::setArrayCopyConvertImpl(InputIt first, InputIt last) {
560 using ValueType =
typename std::iterator_traits<InputIt>::value_type;
561 using Native =
typename TypeConverter<ValueType>::NativeType;
562 const auto& dataType = opcua::getDataType<Native>();
563 const size_t size = std::distance(first, last);
564 auto native = detail::allocateArrayUniquePtr<Native>(size, dataType);
565 for (
size_t i = 0; i < size; ++i) {
566 TypeConverter<ValueType>::toNative(*first++,
native.get()[i]);
568 setArrayImpl(
native.release(), size, dataType, UA_VARIANT_DATA);
577 template <
typename T>
582 template <
typename T>
587 template <
typename T>
592 template <
typename T>
597 template <
typename InputIt>
602 template <
typename InputIt>
610 template <
typename T>
612 var.setScalar(value);
615 template <
typename T>
617 var.setScalar(value, dtype);
620 template <
typename T>
625 template <
typename T>
627 var.setArray(array, dtype);
636 template <
typename T>
638 if constexpr (detail::isRegisteredType<T>) {
639 var.setScalar(value);
641 var.setScalarCopy(value);
645 template <
typename T>
647 var.setScalar(value, dtype);
650 template <
typename T>
652 if constexpr (detail::isRegisteredType<T>) {
655 var.setArrayCopy(array);
659 template <
typename T>
661 var.setArray(array, dtype);
664 template <
typename T>
669 template <
typename T>
View to a contiguous sequence of objects, similar to std::span in C++20.
constexpr iterator begin() const noexcept
constexpr iterator end() const noexcept
Template base class to wrap UA_* type objects.
constexpr TypeWrapper()=default
UA_Variant wrapper class.
void setArrayCopy(const ArrayLike &array, const UA_DataType &dataType)
Copy array to variant with custom data type.
bool isType(Type type) const noexcept
Check if the variant type is equal to the provided type enum.
bool isType(const UA_DataType *dataType) const noexcept
Check if the variant type is equal to the provided data type.
const void * getArray() const
T getScalarCopy() const
Get copy of scalar value with given template type.
Span< T > getArray()
Get array with given template type (only native or wrapper types).
std::optional< Type > getVariantType() const noexcept
Get variant type.
const T && getScalar() const &&
Get reference to scalar value with given template type (only native or wrapper types).
void setArray(ArrayLike &&array) noexcept
Assign array to variant (no copy).
const void * data() const noexcept
Get pointer to the underlying data.
void setArray(ArrayLike &&array, const UA_DataType &dataType) noexcept
Assign array to variant with custom data type (no copy).
void setArrayCopy(const ArrayLike &array)
Copy array to variant.
T && getScalar() &&
Get reference to scalar value with given template type (only native or wrapper types).
const UA_DataType * getDataType() const noexcept
Get data type.
Span< const uint32_t > getArrayDimensions() const noexcept
Get array dimensions.
size_t getArrayLength() const noexcept
Get array length or 0 if variant is not an array.
void setArrayCopy(InputIt first, InputIt last)
Copy range of elements as array to variant.
static Variant fromScalar(T &&value)
Create Variant from scalar value.
bool isType(const UA_DataType &dataType) const noexcept
Check if the variant type is equal to the provided data type.
std::vector< T > getArrayCopy() const
Get copy of array with given template type and return it as a std::vector.
static Variant fromScalar(T &&value, const UA_DataType &dataType)
Create Variant from scalar value with custom data type.
void setScalarCopy(const T &value)
Copy scalar value to variant.
static Variant fromArray(InputIt first, InputIt last, const UA_DataType &dataType)
Create Variant from range of elements with custom data type (copy required).
void setScalar(T &value) noexcept
Assign scalar value to variant (no copy).
bool isType(const NodeId &id) const noexcept
Check if the variant type is equal to the provided data type node id.
Span< const T > getArray() const
Get array with given template type (only native or wrapper types).
bool isEmpty() const noexcept
Check if the variant is empty.
void setScalar(T &value, const UA_DataType &dataType) noexcept
Assign scalar value to variant with custom data type (no copy).
static Variant fromArray(ArrayLike &&array, const UA_DataType &dataType)
Create Variant from array with custom data type.
void setScalarCopy(const T &value, const UA_DataType &dataType)
Copy scalar value to variant with custom data type.
static Variant fromArray(InputIt first, InputIt last)
Create Variant from range of elements (copy required).
bool isArray() const noexcept
Check if the variant is an array.
void setArrayCopy(InputIt first, InputIt last, const UA_DataType &dataType)
Copy range of elements as array to variant with custom data type.
const T & getScalar() const &
Get reference to scalar value with given template type (only native or wrapper types).
T & getScalar() &
Get reference to scalar value with given template type (only native or wrapper types).
bool isScalar() const noexcept
Check if the variant is a scalar.
const void * getScalar() const
bool isType() const noexcept
Check if the variant type is equal to the provided template type.
static Variant fromArray(ArrayLike &&array)
Create Variant from array.
void * data() noexcept
Get pointer to the underlying data.
constexpr const T & native() const noexcept
constexpr T * handle() noexcept
Return pointer to native object.
constexpr T copy(const T &src, const UA_DataType &type) noexcept(isPointerFree< T >)
constexpr void clear(T &native, const UA_DataType &type) noexcept
uint16_t TypeIndex
Type index of the UA_TYPES array.
VariantPolicy
Policies for variant factory methods Variant::fromScalar, Variant::fromArray.
@ ReferenceIfPossible
Favor referencing but fall back to copying if necessary.
@ Copy
Store copy of scalar/array inside the variant.
@ Reference
Store reference to scalar/array inside the variant.
static void setArray(Variant &var, Span< T > array)
static void setArray(Variant &var, Span< T > array, const UA_DataType &dtype)
static void setScalar(Variant &var, const T &value, const UA_DataType &dtype)
static void setArray(Variant &var, InputIt first, InputIt last, const UA_DataType &dtype)
static void setArray(Variant &var, InputIt first, InputIt last)
static void setScalar(Variant &var, const T &value)
static void setScalar(Variant &var, T &value, const UA_DataType &dtype) noexcept
static void setArray(Variant &var, Span< const T > array)
static void setScalar(Variant &var, T &value) noexcept(detail::isRegisteredType< T >)
static void setArray(Variant &var, Span< const T > array, const UA_DataType &dtype)
static void setArray(Variant &var, Span< T > array) noexcept(detail::isRegisteredType< T >)
static void setArray(Variant &var, Span< T > array, const UA_DataType &dtype) noexcept
static void setScalar(Variant &var, T &value) noexcept
static void setArray(Variant &var, Span< T > array, const UA_DataType &dtype) noexcept
static void setArray(Variant &var, Span< T > array) noexcept
static void setScalar(Variant &var, T &value, const UA_DataType &dtype) noexcept
#define UA_EMPTY_ARRAY_SENTINEL
UA_DATATYPEKIND_DIAGNOSTICINFO
const UA_DataType UA_TYPES[191]