13namespace opcua::detail {
18constexpr bool isPointerFree = IsOneOf<
36constexpr bool isBorrowed(
const T& )
noexcept {
40constexpr bool isBorrowed(
const UA_Variant& native)
noexcept {
44constexpr bool isBorrowed(
const UA_DataValue& native)
noexcept {
53constexpr bool isValidTypeCombination(
const UA_DataType& type) {
54 if constexpr (std::is_void_v<T>) {
57 return sizeof(T) == type.
memSize;
62constexpr void clear(T& native,
const UA_DataType& type)
noexcept {
63 assert(isValidTypeCombination<T>(type));
65 if constexpr (isPointerFree<T>) {
67 }
else if (isBorrowed(native)) {
75void deallocate(T* native,
const UA_DataType& type)
noexcept {
76 assert(isValidTypeCombination<T>(type));
82 assert(isValidTypeCombination<T>(type));
83 auto* result =
static_cast<T*
>(
UA_new(&type));
84 if (result ==
nullptr) {
85 throw std::bad_alloc{};
91[[nodiscard]]
auto allocateUniquePtr(
const UA_DataType& type) {
92 auto deleter = [&type](T* native) { deallocate(native, type); };
93 return std::unique_ptr<T, decltype(deleter)>(allocate<T>(type), deleter);
97[[nodiscard]]
constexpr T copy(
const T& src,
const UA_DataType& type)
noexcept(isPointerFree<T>) {
98 assert(isValidTypeCombination<T>(type));
99 if constexpr (!isPointerFree<T>) {
121inline constexpr uintptr_t emptyArraySentinel = 0x01;
124T* stripEmptyArraySentinel(T* array)
noexcept {
126 return reinterpret_cast<T*
>(
reinterpret_cast<uintptr_t
>(array) & ~emptyArraySentinel);
130void deallocateArray(T* array)
noexcept {
131 UA_free(stripEmptyArraySentinel(array));
135void deallocateArray(T* array,
size_t size,
const UA_DataType& type)
noexcept {
136 assert(isValidTypeCombination<T>(type));
137 std::for_each_n(array, size, [&](
auto& item) { clear(item, type); });
138 deallocateArray(array);
142[[nodiscard]] T* allocateArray(
size_t size) {
143 if (size > UA_INT32_MAX) {
144 throw std::bad_alloc{};
147 return reinterpret_cast<T*
>(emptyArraySentinel);
149 auto* result =
static_cast<T*
>(
UA_calloc(size,
sizeof(T)));
150 if (result ==
nullptr) {
151 throw std::bad_alloc{};
157[[nodiscard]] T* allocateArray(
size_t size, [[maybe_unused]]
const UA_DataType& type) {
158 assert(isValidTypeCombination<T>(type));
159 return allocateArray<T>(size);
163[[nodiscard]]
auto allocateArrayUniquePtr(
size_t size,
const UA_DataType& type) {
164 auto deleter = [&type, size](T* native) { deallocateArray(native, size, type); };
165 return std::unique_ptr<T, decltype(deleter)>(allocateArray<T>(size, type), deleter);
169[[nodiscard]] T* copyArray(
const T* src,
size_t size) {
170 T* dst = allocateArray<T>(size);
171 if (src ==
nullptr) {
174 std::memcpy(dst, src, size *
sizeof(T));
179[[nodiscard]] T* copyArray(
const T* src,
size_t size,
const UA_DataType& type) {
180 T* dst = allocateArray<T>(size, type);
181 if (src ==
nullptr) {
184 if constexpr (!isPointerFree<T>) {
186 std::transform(src, src + size, dst, [&](
const T& item) {
return copy(item, type); });
188 std::memcpy(dst, src, size *
sizeof(T));
194void resizeArray(T*& array,
size_t& size,
size_t newSize,
const UA_DataType& type) {
195 if (array ==
nullptr || newSize == size) {
198 T* newArray = allocateArray<T>(newSize, type);
199 std::memcpy(newArray, array, std::min(size, newSize) *
sizeof(T));
200 if (newSize > size) {
201 std::memset(newArray + size, 0, newSize - size);
203 deallocateArray<T>(array, size, type);
constexpr void throwIfBad(UA_StatusCode code)
Check the status code and throw a BadStatus exception if the status code is bad.
UA_StatusCode UA_copy(const void *src, void *dst, const UA_DataType *type)
_UA_BEGIN_DECLS typedef bool UA_Boolean
UA_EXTENSIONOBJECT_DECODED_NODELETE
void * UA_new(const UA_DataType *type)
void UA_clear(void *p, const UA_DataType *type)
void UA_delete(void *p, const UA_DataType *type)