15namespace opcua::detail {
39constexpr bool isValidTypeCombination(
const UA_DataType& type) {
40 if constexpr (std::is_void_v<T>) {
43 return sizeof(T) == type.
memSize;
48constexpr void clear(T& native,
const UA_DataType& type)
noexcept {
49 assert(isValidTypeCombination<T>(type));
50 if constexpr (IsPointerFree<T>::value) {
58void deallocate(T* native)
noexcept {
63void deallocate(T* native,
const UA_DataType& type)
noexcept {
64 assert(isValidTypeCombination<T>(type));
69[[nodiscard]] T* allocate() {
70 auto* ptr =
static_cast<T*
>(
UA_calloc(1,
sizeof(T)));
72 throw std::bad_alloc{};
79 assert(isValidTypeCombination<T>(type));
80 auto* ptr =
static_cast<T*
>(
UA_new(&type));
82 throw std::bad_alloc{};
88[[nodiscard]]
auto allocateUniquePtr(
const UA_DataType& type) {
89 auto deleter = [&type](T* native) { deallocate(native, type); };
90 return std::unique_ptr<T, decltype(deleter)>(allocate<T>(type), deleter);
94[[nodiscard]]
constexpr T copy(
const T& src,
const UA_DataType& type) {
95 assert(isValidTypeCombination<T>(type));
96 if constexpr (IsPointerFree<T>::value) {
106[[nodiscard]]
constexpr auto copy(T&& src,
const UA_DataType& type) {
107 if constexpr (std::is_rvalue_reference_v<
decltype(src)>) {
108 return std::forward<T>(src);
110 return copy(std::as_const(src), type);
127inline constexpr uintptr_t emptyArraySentinel = 0x01;
130[[nodiscard]] T* stripEmptyArraySentinel(T* array)
noexcept {
132 return reinterpret_cast<T*
>(
reinterpret_cast<uintptr_t
>(array) & ~emptyArraySentinel);
136void deallocateArray(T* array)
noexcept {
137 UA_free(stripEmptyArraySentinel(array));
141void deallocateArray(T* array,
size_t size,
const UA_DataType& type)
noexcept {
142 assert(isValidTypeCombination<T>(type));
143 std::for_each_n(array, size, [&](
auto& item) { clear(item, type); });
144 deallocateArray(array);
148[[nodiscard]] T* allocateArray(
size_t size) {
149 if (size > UA_INT32_MAX) {
150 throw std::bad_alloc{};
153 return reinterpret_cast<T*
>(emptyArraySentinel);
155 auto* ptr =
static_cast<T*
>(
UA_calloc(size,
sizeof(T)));
156 if (ptr ==
nullptr) {
157 throw std::bad_alloc{};
163[[nodiscard]] T* allocateArray(
size_t size, [[maybe_unused]]
const UA_DataType& type) {
164 assert(isValidTypeCombination<T>(type));
165 return allocateArray<T>(size);
169[[nodiscard]]
auto allocateArrayUniquePtr(
size_t size,
const UA_DataType& type) {
170 auto deleter = [&type, size](T* native) { deallocateArray(native, size, type); };
171 return std::unique_ptr<T, decltype(deleter)>(allocateArray<T>(size, type), deleter);
175[[nodiscard]] T* copyArray(
const T* src,
size_t size) {
176 T* dst = allocateArray<T>(size);
177 if (src ==
nullptr) {
180 std::memcpy(dst, src, size *
sizeof(T));
185[[nodiscard]] T* copyArray(
const T* src,
size_t size,
const UA_DataType& type) {
186 T* dst = allocateArray<T>(size, type);
187 if (src ==
nullptr) {
190 if constexpr (!IsPointerFree<T>::value) {
192 std::transform(src, src + size, dst, [&](
const T& item) {
return copy(item, type); });
194 std::memcpy(dst, src, size *
sizeof(T));
200void resizeArray(T*& array,
size_t& size,
size_t newSize,
const UA_DataType& type) {
201 if (array ==
nullptr || newSize == size) {
204 T* newArray = allocateArray<T>(newSize, type);
205 std::memcpy(newArray, array, std::min(size, newSize) *
sizeof(T));
206 if (newSize > size) {
207 std::memset(newArray + size, 0, newSize - size);
209 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)
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)