/* Copyright 2016-2020 The MathWorks, Inc. */ #ifndef MATLAB_EXTDATA_REFERENCE_HELPERS_HPP #define MATLAB_EXTDATA_REFERENCE_HELPERS_HPP #include "publish_util.hpp" #include "FunctionType.hpp" #include "StringHelpers.hpp" #include "exception_interface.hpp" #include "ExceptionHelpers.hpp" #include "FunctionType.hpp" #include #include #include #include namespace matlab { namespace data { template class Reference; namespace impl { class ObjectImpl; } namespace detail { template inline typename std::enable_if::value && !std::is_same::value>::type validateReference(ReferenceImpl* impl, bool unshare) { typedef int(*TypedArrayReferenceValidateTypeFcnPtr)(ReferenceImpl*, int, bool); static const TypedArrayReferenceValidateTypeFcnPtr fcn = resolveFunction (FunctionType::TYPED_ARRAY_REFERENCE_VALIDATE_TYPE); throwIfError(fcn(impl, static_cast(U::type), false)); } template inline typename std::enable_if::value && std::is_same::value>::type validateReference(ReferenceImpl* impl, bool unshare) { throwIfError(static_cast(ExceptionType::InvalidDataType)); } template inline typename std::enable_if::value>::type validateReference(ReferenceImpl* impl, bool unshare) { static_assert(std::is_same::value, "Reference type must match array type"); typedef int(*ReferenceValidateIndexFcnPtr)(ReferenceImpl*); static const ReferenceValidateIndexFcnPtr fcn = resolveFunction (FunctionType::REFERENCE_VALIDATE_INDEX); throwIfError(fcn(impl)); } template inline typename std::enable_if::value>::type validateUntypedReference(ReferenceImpl* impl) { typedef int(*TypedArrayReferenceValidateTypeFcnPtr)(ReferenceImpl*, int, bool); static const TypedArrayReferenceValidateTypeFcnPtr fcn = resolveFunction (FunctionType::TYPED_ARRAY_REFERENCE_VALIDATE_TYPE); throwIfError(fcn(impl, static_cast(T::type), false)); } template inline typename std::enable_if::value>::type validateUntypedReference(ReferenceImpl* impl) { typedef int(*ReferenceValidateTypeFcnPtr)(ReferenceImpl*, int); static const ReferenceValidateTypeFcnPtr fcn = resolveFunction (FunctionType::REFERENCE_VALIDATE_TYPE); throwIfError(fcn(impl, static_cast(GetArrayType::type))); } template inline typename std::enable_if::value>::type validateUntypedArrayReference(ReferenceImpl* impl) { typedef int(*TypedArrayReferenceValidateTypeFcnPtr)(ReferenceImpl*, int, bool); static const TypedArrayReferenceValidateTypeFcnPtr fcn = resolveFunction (FunctionType::TYPED_ARRAY_REFERENCE_VALIDATE_TYPE); throwIfError(fcn(impl, static_cast(GetArrayType::type), false)); } template inline typename std::enable_if::value>::type validateUntypedArrayReference(ReferenceImpl* impl) { typedef int(*TypedArrayReferenceValidateTypeFcnPtr)(ReferenceImpl*, int, bool); static const TypedArrayReferenceValidateTypeFcnPtr fcn = resolveFunction (FunctionType::TYPED_ARRAY_REFERENCE_VALIDATE_TYPE); throwIfError(fcn(impl, static_cast(GetArrayType::type), false)); } template inline T castToType(void* value, ArrayType type) { switch (type) { case ArrayType::LOGICAL: return static_cast(*static_cast(value)); case ArrayType::DOUBLE: return static_cast(*static_cast(value)); case ArrayType::SINGLE: return static_cast(*static_cast(value)); case ArrayType::INT64: return static_cast(*static_cast(value)); case ArrayType::INT32: return static_cast(*static_cast(value)); case ArrayType::INT16: return static_cast(*static_cast(value)); case ArrayType::INT8: return static_cast(*static_cast(value)); case ArrayType::UINT64: return static_cast(*static_cast(value)); case ArrayType::UINT32: return static_cast(*static_cast(value)); case ArrayType::UINT16: return static_cast(*static_cast(value)); case ArrayType::UINT8: return static_cast(*static_cast(value)); default: throw TypeMismatchException(std::string("Can't convert this element")); } return T(); } template <> inline bool castToType(void* value, ArrayType type) { switch (type) { case ArrayType::LOGICAL: return *static_cast(value); case ArrayType::DOUBLE: return *static_cast(value) != 0; case ArrayType::SINGLE: return *static_cast(value) != 0; case ArrayType::INT64: return *static_cast(value) != 0; case ArrayType::INT32: return *static_cast(value) != 0; case ArrayType::INT16: return *static_cast(value) != 0; case ArrayType::INT8: return *static_cast(value) != 0; case ArrayType::UINT64: return *static_cast(value) != 0; case ArrayType::UINT32: return *static_cast(value) != 0; case ArrayType::UINT16: return *static_cast(value) != 0; case ArrayType::UINT8: return *static_cast(value) != 0; default: throw TypeMismatchException(std::string("Can't convert this element")); } return false; } template <> inline CHAR16_T castToType(void* value, ArrayType type) { switch (type) { case ArrayType::CHAR: return *static_cast(value); default: throw TypeMismatchException(std::string("Can't convert this element")); } return false; } template inline typename std::enable_if::value, U&>::type getElement(std::shared_ptr impl) { void* value = nullptr; typedef int(*TypedReferenceGetPodValueFcnPtr)(ReferenceImpl*, void**); static const TypedReferenceGetPodValueFcnPtr fcn = resolveFunction (FunctionType::TYPED_REFERENCE_GET_POD_VALUE); throwIfError(fcn(impl.get(), &value)); return *(static_cast(value)); } template inline typename std::enable_if::value, U>::type getElement(std::shared_ptr impl) { void* real = nullptr; void* imag = nullptr; typedef int(*TypedReferenceGetComplexValueFcnPtr)(ReferenceImpl*, void**, void**); static const TypedReferenceGetComplexValueFcnPtr fcn = resolveFunction (FunctionType::TYPED_REFERENCE_GET_COMPLEX_VALUE); throwIfError(fcn(impl.get(), &real, &imag)); typename U::value_type r = *(static_cast(real)); typename U::value_type i = *(static_cast(imag)); return U(r,i); } template inline typename std::enable_if::value, MATLABString>::type getElement(std::shared_ptr impl) { const char16_t* str = nullptr; size_t strlen = 0; typedef int(*StringGetValueFcnPtr)(ReferenceImpl*, const char16_t**, size_t*); static const StringGetValueFcnPtr fcn = resolveFunction (FunctionType::STRING_GET_VALUE); throwIfError(fcn(impl.get(), &str, &strlen)); if (str != nullptr) { return MATLABString(String(str, strlen)); } return MATLABString(); } template inline typename std::enable_if::value, Array>::type getElement(std::shared_ptr impl) { impl::ArrayImpl* arr_impl = nullptr; typedef void(*ArrayReferenceSharedCopyFcnPtr)(ReferenceImpl*, matlab::data::impl::ArrayImpl**); static const ArrayReferenceSharedCopyFcnPtr fcn = resolveFunction (FunctionType::ARRAY_REFERENCE_SHARED_COPY); fcn(impl.get(), &arr_impl); return Access::createObj(arr_impl); } template inline typename std::enable_if::value, Struct>::type getElement(std::shared_ptr impl) { return Access::createObj(impl); } template inline typename std::enable_if::value, Object>::type getElement(std::shared_ptr impl) { impl::ObjectImpl* obj_impl = nullptr; char msg[100]; typedef int(*ObjectSharedCopyFcnPtr)(ReferenceImpl*, impl::ObjectImpl**, char*); static const ObjectSharedCopyFcnPtr fcn = resolveFunction (FunctionType::OBJECT_SHARED_COPY); auto res = fcn(impl.get(), &obj_impl, msg); throwIfError(res, std::string(msg)); return Access::createObj(obj_impl); } template inline typename std::enable_if::value>::type setElement(ReferenceImpl* impl, U rhs, int type) { typedef int(*TypedReferenceSetPodValueFcnPtr)(ReferenceImpl*, int, void*); static const TypedReferenceSetPodValueFcnPtr fcn = resolveFunction (FunctionType::TYPED_REFERENCE_SET_POD_VALUE); throwIfError(fcn(impl, type, &rhs)); } template inline typename std::enable_if::value>::type setElement(ReferenceImpl* impl, U rhs, int type) { typename U::value_type real = rhs.real(); typename U::value_type imag = rhs.imag(); typedef int(*TypedReferenceSetComplexValueFcnPtr)(ReferenceImpl*, int, void*, void*); static const TypedReferenceSetComplexValueFcnPtr fcn = resolveFunction (FunctionType::TYPED_REFERENCE_SET_COMPLEX_VALUE); throwIfError(fcn(impl, type, &real, &imag)); } template inline typename std::enable_if::value>::type setElement(ReferenceImpl* impl, U rhs, int) { typedef int(*ReferenceSetChar16StringFcnPtr)(ReferenceImpl*, const char16_t*, size_t); static const ReferenceSetChar16StringFcnPtr fcn = resolveFunction (FunctionType::REFERENCE_SET_CHAR16_STRING); throwIfError(fcn(impl, rhs.c_str(), rhs.size())); } template inline typename std::enable_if::value>::type setElement(ReferenceImpl* impl, U rhs, int) { typedef int(*ReferenceSetStringFcnPtr)(ReferenceImpl*, const char*, size_t); static const ReferenceSetStringFcnPtr fcn = resolveFunction (FunctionType::REFERENCE_SET_STRING); throwIfError(fcn(impl, rhs.c_str(), rhs.size())); } template inline typename std::enable_if::value>::type setElement(ReferenceImpl* impl, U rhs, int) { typedef int(*ReferenceSetReferenceValueFcnPtr)(ReferenceImpl*, matlab::data::impl::ArrayImpl*); static const ReferenceSetReferenceValueFcnPtr fcn = resolveFunction (FunctionType::REFERENCE_SET_REFERENCE_VALUE); throwIfError(fcn(impl, Access::getImpl(rhs))); } template inline typename std::enable_if::value, Object>::type setElement(ReferenceImpl* impl, U rhs, int) { char msg[100]; typedef int(*ReferenceSetReferenceObjectFcnPtr)(ReferenceImpl*, matlab::data::impl::ObjectImpl*, char*); static const ReferenceSetReferenceObjectFcnPtr fcn = resolveFunction (FunctionType::REFERENCE_SET_REFERENCE_OBJECT); auto res = fcn(impl, Access::getImpl(rhs), msg); throwIfError(res, std::string(msg)); return rhs; } template inline typename std::enable_if::value>::type setElement(ReferenceImpl* impl, U rhs, int) { if (rhs) { String elem = *rhs; typedef int(*ReferenceSetChar16StringFcnPtr)(ReferenceImpl*, const char16_t*, size_t); static const ReferenceSetChar16StringFcnPtr fcn = resolveFunction (FunctionType::REFERENCE_SET_CHAR16_STRING); throwIfError(fcn(impl, elem.c_str(), elem.size())); } else { typedef int(*ReferenceSetMissingChar16StringFcnPtr)(ReferenceImpl*); static const ReferenceSetMissingChar16StringFcnPtr fcn = resolveFunction (FunctionType::REFERENCE_SET_MISSING_CHAR16_STRING); throwIfError(fcn(impl)); } } template inline typename std::enable_if::value && !std::is_same::value, std::string>::type getString(ReferenceImpl* impl) { throwIfError(static_cast(ExceptionType::InvalidDataType)); } template inline typename std::enable_if::value, std::string>::type getString(ReferenceImpl* impl) { const char* str = nullptr; size_t strlen = 0; typedef int(*EnumArrayGetValueFcnPtr)(ReferenceImpl*, const char**, size_t*); static const EnumArrayGetValueFcnPtr fcn = resolveFunction (FunctionType::ENUM_ARRAY_GET_VALUE); throwIfError(fcn(impl, &str, &strlen)); return std::string(str, strlen); } template inline typename std::enable_if::value, std::string>::type getString(ReferenceImpl* impl) { const char16_t* str = nullptr; size_t strlen = 0; bool missing = false; typedef int(*StringGetValueFcnPtr)(ReferenceImpl* impl, const char16_t**, size_t*); static const StringGetValueFcnPtr fcn = resolveFunction (FunctionType::STRING_GET_VALUE); throwIfError(fcn(impl, &str, &strlen)); if (str == nullptr) { throw std::runtime_error("Missing string"); } String temp(str, strlen); if (!isAscii7(temp)) { throw NonAsciiCharInInputDataException(std::string("Input data can only contain ASCII characters")); } return toAsciiHelper(str, strlen); } template inline typename std::enable_if::value && !std::is_same::value>::type setString(ReferenceImpl* impl, std::string rhs) { throwIfError(static_cast(ExceptionType::InvalidDataType)); } template inline typename std::enable_if::value>::type setString(ReferenceImpl* impl, std::string rhs) { typedef int(*EnumArraySetValueFcnPtr)(ReferenceImpl*, const char*, size_t); static const EnumArraySetValueFcnPtr fcn = resolveFunction (FunctionType::ENUM_ARRAY_SET_VALUE); throwIfError(fcn(impl, rhs.c_str(), rhs.size())); } template inline typename std::enable_if::value>::type setString(ReferenceImpl* impl, std::string rhs) { if (!isAscii7(rhs)) { throw NonAsciiCharInInputDataException(std::string("Input data can only contain ASCII characters")); } String tmp(rhs.begin(), rhs.end()); setElement(impl, std::move(tmp), 0); } template inline typename std::enable_if::value>::type setString(ReferenceImpl* impl, String rhs) { setElement(impl, std::move(rhs), 0); } template inline typename std::enable_if::value>::type setString(ReferenceImpl* impl, MATLABString rhs) { setElement(impl, std::move(rhs), 0); } inline ReferenceImpl* getRef(ReferenceImpl* impl, const char* field, size_t len, bool unshare) { ReferenceImpl* retVal = nullptr; size_t numIdx = 0; typedef int(*StructReferenceGetIndexFcnPtr)(ReferenceImpl*, const char*, size_t, size_t*); static const StructReferenceGetIndexFcnPtr fcn = resolveFunction (FunctionType::STRUCT_REFERENCE_GET_INDEX); throwIfError(fcn(impl, field, len, &numIdx)); typedef int(*ReferenceGetReferenceValueFcnPtr)(ReferenceImpl*, bool, ReferenceImpl**); static const ReferenceGetReferenceValueFcnPtr fcn2 = resolveFunction (FunctionType::REFERENCE_GET_REFERENCE_VALUE); fcn2(impl, unshare, &retVal); typedef int(*ReferenceAddIndexFcnPtr)(ReferenceImpl*, size_t); static const ReferenceAddIndexFcnPtr fcn3 = resolveFunction (FunctionType::REFERENCE_ADD_INDEX); fcn3(retVal, numIdx); return retVal; } template typename std::enable_if::value, T>::type castTo(std::shared_ptr impl) { void* value = nullptr; typedef int(*TypedReferenceGetPodValueFcnPtr)(ReferenceImpl*, void**); static const TypedReferenceGetPodValueFcnPtr fcn = resolveFunction (FunctionType::TYPED_REFERENCE_GET_POD_VALUE); throwIfError(fcn(impl.get(), &value)); typedef int(*ReferenceGetContainerTypeFcnPtr)(ReferenceImpl*, int*); static const ReferenceGetContainerTypeFcnPtr fcn2 = resolveFunction (FunctionType::REFERENCE_GET_CONTAINER_TYPE); int type; throwIfError(fcn2(impl.get(), &type)); return castToType(value, static_cast(type)); } template typename std::enable_if::value, T>::type castTo(std::shared_ptr impl) { typedef int(*TypedArrayReferenceValidateTypeFcnPtr)(ReferenceImpl*, int, bool); static const TypedArrayReferenceValidateTypeFcnPtr fcn2 = resolveFunction (FunctionType::TYPED_ARRAY_REFERENCE_VALIDATE_TYPE); throwIfError(fcn2(impl.get(), static_cast(T::type), false)); impl::ArrayImpl* arr_impl = nullptr; typedef void(*ArrayReferenceSharedCopyFcnPtr)(ReferenceImpl*, matlab::data::impl::ArrayImpl**); static const ArrayReferenceSharedCopyFcnPtr fcn = resolveFunction (FunctionType::ARRAY_REFERENCE_SHARED_COPY); fcn(impl.get(), &arr_impl); return Access::createObj(arr_impl); } template typename std::enable_if::value, T>::type castTo(std::shared_ptr impl) { void* real = nullptr; void* imag = nullptr; typedef int(*TypedReferenceGetComplexValueFcnPtr)(ReferenceImpl*, void**, void**); static const TypedReferenceGetComplexValueFcnPtr fcn = resolveFunction (FunctionType::TYPED_REFERENCE_GET_COMPLEX_VALUE); throwIfError(fcn(impl.get(), &real, &imag)); typename T::value_type r = *(static_cast(real)); typename T::value_type i = *(static_cast(imag)); return T(r,i); } template typename std::enable_if::value, String>::type castTo(std::shared_ptr impl) { typedef int(*ReferenceGetContainerTypeFcnPtr)(ReferenceImpl*, int*); static const ReferenceGetContainerTypeFcnPtr fcn2 = resolveFunction (FunctionType::REFERENCE_GET_CONTAINER_TYPE); int type; throwIfError(fcn2(impl.get(), &type)); if (ArrayType(type) == ArrayType::MATLAB_STRING) { const char16_t* str = nullptr; size_t strlen = 0; typedef int(*StringGetValueFcnPtr)(ReferenceImpl* impl, const char16_t**, size_t*); static const StringGetValueFcnPtr fcn = resolveFunction (FunctionType::STRING_GET_VALUE); throwIfError(fcn(impl.get(), &str, &strlen)); return String(str, strlen); } throw TypeMismatchException(std::string("Can't convert this element to a matlab::data::String")); } template typename std::enable_if::value, T>::type castTo(std::shared_ptr impl) { static_assert(!is_const_ref, "Can only get a reference to a non const ref"); validateUntypedReference(impl.get()); return Access::createObj(impl); } template typename std::enable_if::value, std::string>::type castTo(std::shared_ptr impl) { typedef int(*ReferenceGetContainerTypeFcnPtr)(ReferenceImpl*, int*); static const ReferenceGetContainerTypeFcnPtr fcn2 = resolveFunction (FunctionType::REFERENCE_GET_CONTAINER_TYPE); int arrType; throwIfError(fcn2(impl.get(), &arrType)); if (ArrayType(arrType) == ArrayType::ENUM) { const char* str = nullptr; size_t strlen = 0; typedef int(*EnumArrayGetValueFcnPtr)(ReferenceImpl* impl, const char**, size_t*); static const EnumArrayGetValueFcnPtr fcn = resolveFunction (FunctionType::ENUM_ARRAY_GET_VALUE); throwIfError(fcn(impl.get(), &str, &strlen)); return std::string(str, strlen); } else if (ArrayType(arrType) == ArrayType::MATLAB_STRING) { const char16_t* str = nullptr; size_t strlen = 0; typedef int(*StringGetValueFcnPtr)(ReferenceImpl* impl, const char16_t**, size_t*); static const StringGetValueFcnPtr fcn = resolveFunction (FunctionType::STRING_GET_VALUE); throwIfError(fcn(impl.get(), &str, &strlen)); String temp(str, strlen); if (!isAscii7(temp)) { throw NonAsciiCharInInputDataException(std::string("Input data can only contain ASCII characters")); } return toAsciiHelper(str, strlen); } throw TypeMismatchException(std::string("Can't convert this element to a std::string")); } } } } #endif