/* Copyright 2016-2017 The MathWorks, Inc. */ #ifndef MATLAB_EXTDATA_REFERENCE_HELPERS_HPP #define MATLAB_EXTDATA_REFERENCE_HELPERS_HPP #include "reference_interface.hpp" #include "string_interface.hpp" #include "struct_interface.hpp" #include "exception_interface.hpp" #include "ExceptionHelpers.hpp" #include namespace matlab { namespace data { template class Reference; namespace detail { template inline typename std::enable_if::value>::type validateReference(ReferenceImpl* impl, bool unshare) { detail::throwIfError(typed_array_reference_validate_type(impl, static_cast(U::type), false)); } 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"); detail::throwIfError(reference_validate_index(impl)); } template inline typename std::enable_if::value>::type validateUntypedReference(ReferenceImpl* impl) { detail::throwIfError(typed_array_reference_validate_type(impl, static_cast(T::type), false)); } template inline typename std::enable_if::value>::type validateUntypedReference(ReferenceImpl* impl) { detail::throwIfError(reference_validate_type(impl, static_cast(GetArrayType::type))); } template inline typename std::enable_if::value>::type validateUntypedArrayReference(ReferenceImpl* impl) { detail::throwIfError(typed_array_reference_validate_type(impl, static_cast(GetArrayType::type), false)); } template inline typename std::enable_if::value>::type validateUntypedArrayReference(ReferenceImpl* impl) { detail::throwIfError(typed_array_reference_validate_type(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; throwIfError(typed_reference_get_pod_value(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; throwIfError(typed_reference_get_complex_value(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) { char16_t* str = nullptr; size_t strlen = 0; throwIfError(string_get_value(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; array_reference_shared_copy(impl.get(), &arr_impl); return detail::Access::createObj(arr_impl); } template inline typename std::enable_if::value, Struct>::type getElement(std::shared_ptr impl) { return detail::Access::createObj(impl); } template inline typename std::enable_if::value>::type setElement(ReferenceImpl* impl, U rhs, int type) { throwIfError(typed_reference_set_pod_value(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(); throwIfError(typed_reference_set_complex_value(impl, type, &real, &imag)); } template inline typename std::enable_if::value>::type setElement(ReferenceImpl* impl, U rhs, int type) { throwIfError(reference_set_char16_string(impl, rhs.c_str(), rhs.size())); } template inline typename std::enable_if::value>::type setElement(ReferenceImpl* impl, U rhs, int type) { throwIfError(reference_set_string(impl, rhs.c_str(), rhs.size())); } template inline typename std::enable_if::value>::type setElement(ReferenceImpl* impl, U rhs, int type) { throwIfError(reference_set_reference_value(impl, detail::Access::getImpl(rhs))); } template inline typename std::enable_if::value>::type setElement(ReferenceImpl* impl, U rhs, int type) { if (rhs) { String elem = *rhs; throwIfError(reference_set_char16_string(impl, elem.c_str(), elem.size())); } else { throwIfError(reference_set_missing_char16_string(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) { char* str = nullptr; size_t strlen = 0; throwIfError(enum_get_value(impl, &str, &strlen)); return std::string(str, strlen); } template inline typename std::enable_if::value, std::string>::type getString(ReferenceImpl* impl) { char16_t* str = nullptr; size_t strlen = 0; bool missing = false; throwIfError(string_get_value(impl, &str, &strlen)); if (str == nullptr) { throw std::runtime_error("Missing string"); } String temp(str, strlen); if (!detail::isAscii7(temp)) { throw NonAsciiCharInInputDataException(std::string("Input data can only contain ASCII characters")); } return std::string(temp.begin(), temp.end()); } 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) { throwIfError(enum_set_value(impl, const_cast(rhs.c_str()), rhs.size())); } template inline typename std::enable_if::value>::type setString(ReferenceImpl* impl, std::string rhs) { if (!detail::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; throwIfError(struct_reference_get_index(impl, field, len, &numIdx)); reference_get_reference_value(impl, unshare, &retVal); reference_add_index(retVal, numIdx); return retVal; } template typename std::enable_if::value, T>::type castTo(std::shared_ptr impl) { void* value = nullptr; detail::throwIfError(reference_get_pod_value(impl.get(), &value)); int type; detail::throwIfError(reference_get_container_type(impl.get(), &type)); return detail::castToType(value, ArrayType(type)); } template typename std::enable_if::value, T>::type castTo(std::shared_ptr impl) { detail::throwIfError(typed_array_reference_validate_type(impl.get(), static_cast(T::type), false)); impl::ArrayImpl* arr_impl = nullptr; array_reference_shared_copy(impl.get(), &arr_impl); return detail::Access::createObj(arr_impl); } template typename std::enable_if::value, T>::type castTo(std::shared_ptr impl) { void* real = nullptr; void* imag = nullptr; detail::throwIfError(reference_get_complex_value(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) { int type; detail::throwIfError(reference_get_container_type(impl.get(), &type)); if (ArrayType(type) == ArrayType::MATLAB_STRING) { char16_t* str = nullptr; size_t strlen = 0; detail::throwIfError(string_get_value(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 detail::Access::createObj(impl); } template typename std::enable_if::value, std::string>::type castTo(std::shared_ptr impl) { int arrType; detail::throwIfError(reference_get_container_type(impl.get(), &arrType)); if (ArrayType(arrType) == ArrayType::ENUM) { char* str = nullptr; size_t strlen = 0; detail::throwIfError(enum_get_value(impl.get(), &str, &strlen)); return std::string(str, strlen); } else if (ArrayType(arrType) == ArrayType::MATLAB_STRING) { char16_t* str = nullptr; size_t strlen = 0; detail::throwIfError(string_get_value(impl.get(), &str, &strlen)); String temp(str, strlen); if (!detail::isAscii7(temp)) { throw NonAsciiCharInInputDataException(std::string("Input data can only contain ASCII characters")); } return std::string(temp.begin(), temp.end()); } throw TypeMismatchException(std::string("Can't convert this element to a std::string")); } } } } #endif