/* Copyright 2017-2020 The MathWorks, Inc. */ #ifndef __MEX_API_ADAPTER_HPP__ #define __MEX_API_ADAPTER_HPP__ #include "MatlabDataArray.hpp" #include "mex.hpp" #include "mexEngineUtilImpl.hpp" #include "mexExceptionType.hpp" #include #include #include "assert.h" #include "../mexMatlabEngine.hpp" LIBMWMEX_API_EXTERN_C{ void mexApiFeval(void*, const int, void**, const int, void**, const char*, int*, void**, void*, void*, void(*)(void*, const char16_t*, size_t), void(*)(void*)); void* mexApiGetVariable(void*, const char*, const char16_t*, int*, void**); void* mexApiSetVariable(void*, void*, const char*, const char16_t*, int*, void**); void* mexApiGetProperty(void*, void*, size_t, const char16_t*, int*, void**); void* mexApiSetProperty(void*, void*, size_t, const char16_t*, void*, int*, void**); uintptr_t mexApiFevalAsync(void*, const int, const int, void**, const char*, bool, void(*)(void*, int, bool, matlab::data::impl::ArrayImpl**), void(*)(void*, int, bool, int, void*), void*, void*, void*, void(*)(void*, const char16_t*, size_t), void(*)(void*)); uintptr_t mexApiEvalAsync(void*, const char16_t*, void(*)(void*), void(*)(void*, int, void*), void*, void*, void*, void(*)(void*, const char16_t*, size_t), void(*)(void*)); uintptr_t mexApiGetVariableAsync(void*, const char*, const char16_t*, void(*)(void*, int, bool, matlab::data::impl::ArrayImpl**), void(*)(void*, int, bool, int, void*), void*); uintptr_t mexApiSetVariableAsync(void*, void*, const char*, const char16_t*, void(*)(void*, int, bool, matlab::data::impl::ArrayImpl**), void(*)(void*, int, bool, int, void*), void*); uintptr_t mexApiGetPropertyAsync(void*, void*, size_t, const char16_t*, void(*)(void*, int, bool, matlab::data::impl::ArrayImpl**), void(*)(void*, int, bool, int, void*), void*); uintptr_t mexApiSetPropertyAsync(void*, void*, size_t, const char16_t*, void*, void(*)(void*, int, bool, matlab::data::impl::ArrayImpl**), void(*)(void*, int, bool, int, void*), void*); bool mexApiCancelFevalWithCompletion(uintptr_t, bool); } namespace matlab { namespace engine { namespace detail { template inline void validateTIsSupported() { using U = typename std::remove_cv::type>::type; static_assert( std::is_same::value || std::is_same::value || std::is_same::value || std::is_same::value || std::is_same::value || std::is_same::value || std::is_same::value || std::is_same::value || std::is_same::value || std::is_same::value || std::is_same::value || std::is_same::value, "Attempted to use unsupported types."); } template matlab::data::Array createRhs(matlab::data::ArrayFactory& factory, T&& value) { validateTIsSupported(); using U = typename std::remove_cv::type>::type; return factory.createArray({ 1, 1 }, { value }); } template matlab::data::Array createRhs(matlab::data::ArrayFactory& factory, std::vector && value) { validateTIsSupported(); return factory.createArray({ 1, value.size() }, value.begin(), value.end()); } template struct index_sequence { using value_type = std::size_t; static std::size_t size() { return sizeof...(Ints); } }; template struct make_index_sequence_impl { using type = typename make_index_sequence_impl::type; }; template struct make_index_sequence_impl < 0, Values... > { using type = index_sequence < Values... >; }; template using make_index_sequence = typename make_index_sequence_impl::type; template struct createLhs { static const size_t nlhs = 1; T operator()(std::vector&& lhs) const { if (lhs.empty()) { throw matlab::engine::TypeConversionException("The result is empty."); } T value; try { value = (*this)(matlab::data::TypedArray(std::move(lhs.front()))); } catch (const std::exception& e) { throw matlab::engine::TypeConversionException(e.what()); } return value; } T operator()(matlab::data::TypedArray lhs) const { validateTIsSupported(); auto const begin = lhs.begin(); auto const end = lhs.end(); if (begin == end) { throw matlab::engine::TypeConversionException("The result is empty."); } return *begin; } }; template<> struct createLhs < void > { static const size_t nlhs = 0; void operator()(std::vector&& lhs) const {} }; template struct createLhs < std::tuple > { static const size_t nlhs = sizeof...(TupleTypes); using T = std::tuple < TupleTypes... >; T operator()(std::vector&& lhs) const { //we are not validating the LHS here as it can be any combinations of types for std::tuple. if (lhs.size() < sizeof...(TupleTypes)) { throw std::runtime_error(""); } return (*this)(std::move(lhs), detail::make_index_sequence()); } private: template using TupleElement = typename std::remove_cv >::type>::type>::type; template std::tuple operator()(std::vector&& lhs, detail::index_sequence) const { return std::tuple (createLhs>()(std::move(lhs[IndexList]))...); } }; } } } void implDeleter(matlab::data::impl::ArrayImpl** impl) { if (impl != nullptr) free(impl); } inline void writeToStreamBuffer(void* buffer, const char16_t* stream, size_t n) { std::shared_ptr* output = reinterpret_cast*>(buffer); output->get()->sputn(stream, n); } inline void deleteStreamBufferImpl(void* impl) { delete static_cast*>(impl); } /*** matlab::engine::MATLABEngine ***/ std::vector matlab::engine::MATLABEngine::feval(const std::u16string &function, const int nlhs, const std::vector &args, const std::shared_ptr &output, const std::shared_ptr &error) { int nrhs = static_cast(args.size()); matlab::data::impl::ArrayImpl** plhs_arr_impl = (nlhs == 0) ? nullptr : (matlab::data::impl::ArrayImpl**) malloc(sizeof(matlab::data::impl::ArrayImpl*) * nlhs); std::unique_ptr plhs_impl_guard(plhs_arr_impl, &implDeleter); matlab::data::impl::ArrayImpl** args_arr_impl = (nrhs == 0) ? nullptr : (matlab::data::impl::ArrayImpl**) malloc(sizeof(matlab::data::impl::ArrayImpl*) * nrhs); std::unique_ptr args_impl_guard(args_arr_impl, &implDeleter); void** plhs_impl = reinterpret_cast(plhs_arr_impl); void** args_impl = reinterpret_cast(args_arr_impl); arrayToImpl(nrhs, args_impl, args); void* mexcept = nullptr; std::string function_utf8 = matlab::engine::convertUTF16StringToUTF8String(function); void* output_ = output ? new std::shared_ptr(std::move(output)) : nullptr; void* error_ = error ? new std::shared_ptr(std::move(error)) : nullptr; int errID = 0; mexApiFeval(pImpl, nlhs, plhs_impl, nrhs, args_impl, function_utf8.c_str(), &errID, &mexcept, output_, error_, &writeToStreamBuffer, &deleteStreamBufferImpl); throwIfError(errID, mexcept); std::vector plhs; plhs.reserve(nlhs); implToArray(nlhs, plhs_impl, plhs); return plhs; } std::vector matlab::engine::MATLABEngine::feval(const std::string &function, const int nlhs, const std::vector &args, const std::shared_ptr &output, const std::shared_ptr &error) { return feval(std::u16string(function.begin(), function.end()), nlhs, args, output, error); } matlab::data::Array matlab::engine::MATLABEngine::feval(const std::u16string &function, const std::vector &args, const std::shared_ptr &output, const std::shared_ptr &error) { std::vector out_vec = feval(function, 1, args, output, error); return out_vec.at(0); } matlab::data::Array matlab::engine::MATLABEngine::feval(const std::string &function, const std::vector &args, const std::shared_ptr &output, const std::shared_ptr &error) { return feval(std::u16string(function.begin(), function.end()), args, output, error); } matlab::data::Array matlab::engine::MATLABEngine::feval(const std::u16string &function, const matlab::data::Array &arg, const std::shared_ptr &output, const std::shared_ptr &error) { return feval(function, std::vector({ arg }), output, error); } matlab::data::Array matlab::engine::MATLABEngine::feval(const std::string &function, const matlab::data::Array &arg, const std::shared_ptr &output, const std::shared_ptr &error) { return feval(std::u16string(function.begin(), function.end()), std::vector({arg}), output, error); } template ReturnType matlab::engine::MATLABEngine::feval(const std::u16string &function, const std::shared_ptr &output, const std::shared_ptr &error, RhsArgs&&... rhsArgs) { matlab::data::ArrayFactory factory; std::vector rhsList({ detail::createRhs(factory, std::forward(rhsArgs))... }); auto const nlhs = detail::createLhs::nlhs; std::vector f = feval(function, nlhs, rhsList, output, error); detail::createLhs lhsFactory; return lhsFactory(std::move(f)); } template ReturnType matlab::engine::MATLABEngine::feval(const std::string &function, const std::shared_ptr &output, const std::shared_ptr &error, RhsArgs&&... rhsArgs) { return feval(std::u16string(function.begin(), function.end()), output, error, std::forward(rhsArgs)...); } template ReturnType matlab::engine::MATLABEngine::feval(const std::u16string &function, RhsArgs&&... rhsArgs) { const std::shared_ptr defaultStream; return feval(function, defaultStream, defaultStream, std::forward(rhsArgs)...); } template ReturnType matlab::engine::MATLABEngine::feval(const std::string &function, RhsArgs&&... rhsArgs) { return feval(std::u16string(function.begin(), function.end()), std::forward(rhsArgs)...); } void matlab::engine::MATLABEngine::eval(const std::u16string &str, const std::shared_ptr &output, const std::shared_ptr &error) { matlab::data::ArrayFactory factory; auto mStr = factory.createScalar(str); feval(matlab::engine::convertUTF8StringToUTF16String("eval"), 0, std::vector({ mStr }), output, error); } matlab::data::Array matlab::engine::MATLABEngine::getVariable(const std::u16string &varName, matlab::engine::WorkspaceType workspaceType) { const char* workspace = (workspaceType == matlab::engine::WorkspaceType::BASE) ? "base" : "global"; void* mexcept = nullptr; int errID = 0; void* res = mexApiGetVariable(pImpl, workspace, varName.c_str(), &errID, &mexcept); throwIfError(errID, mexcept); matlab::data::Array ret = getArray(res); return ret; } matlab::data::Array matlab::engine::MATLABEngine::getVariable(const std::string &varName, matlab::engine::WorkspaceType workspaceType) { return getVariable(std::u16string(varName.begin(), varName.end()), workspaceType); } void matlab::engine::MATLABEngine::setVariable(const std::u16string &varName, const matlab::data::Array &var, matlab::engine::WorkspaceType workspaceType) { const char* workspace = (workspaceType == matlab::engine::WorkspaceType::BASE) ? "base" : "global"; void* mexcept = nullptr; void* varImpl = matlab::data::detail::Access::getImpl(var); int errID = 0; mexApiSetVariable(pImpl, varImpl, workspace, varName.c_str(), &errID, &mexcept); throwIfError(errID, mexcept); } void matlab::engine::MATLABEngine::setVariable(const std::string &varName, const matlab::data::Array &var, matlab::engine::WorkspaceType workspaceType) { setVariable(std::u16string(varName.begin(), varName.end()), var, workspaceType); } matlab::data::Array matlab::engine::MATLABEngine::getProperty(const matlab::data::Array &object, size_t index, const std::u16string &propertyName) { void* mexcept = nullptr; void* objImpl = matlab::data::detail::Access::getImpl(object); int errID = 0; void* impl = mexApiGetProperty(pImpl, objImpl, index, propertyName.c_str(), &errID, &mexcept); throwIfError(errID, mexcept); return matlab::data::detail::Access::createObj(reinterpret_cast(impl)); } matlab::data::Array matlab::engine::MATLABEngine::getProperty(const matlab::data::Array &object, size_t index, const std::string &propertyName) { return getProperty(object, index, std::u16string(propertyName.begin(), propertyName.end())); } matlab::data::Array matlab::engine::MATLABEngine::getProperty(const matlab::data::Array &object, const std::u16string &propertyName) { return getProperty(object, 0, propertyName); } matlab::data::Array matlab::engine::MATLABEngine::getProperty(const matlab::data::Array &object, const std::string &propertyName) { return getProperty(object, 0, std::u16string(propertyName.begin(), propertyName.end())); } void matlab::engine::MATLABEngine::setProperty(matlab::data::Array &object, size_t index, const std::u16string &propertyName, const matlab::data::Array &value) { void* mexcept = nullptr; void* objImpl = matlab::data::detail::Access::getImpl(object); void* propertyImpl = matlab::data::detail::Access::getImpl(value); int errID = 0; void* impl = mexApiSetProperty(pImpl, objImpl, index, propertyName.c_str(), propertyImpl, &errID, &mexcept); throwIfError(errID, mexcept); object = matlab::data::detail::Access::createObj(reinterpret_cast(impl)); } void matlab::engine::MATLABEngine::setProperty(matlab::data::Array &object, size_t index, const std::string &propertyName, const matlab::data::Array &value) { setProperty(object, index, std::u16string(propertyName.begin(), propertyName.end()), value); } void matlab::engine::MATLABEngine::setProperty(matlab::data::Array &object, const std::u16string &propertyName, const matlab::data::Array &value) { setProperty(object, 0, propertyName, value); } void matlab::engine::MATLABEngine::setProperty(matlab::data::Array &object, const std::string &propertyName, const matlab::data::Array &value) { setProperty(object, 0, std::u16string(propertyName.begin(), propertyName.end()), value); } namespace { template void set_promise_exception(void *p, int excTypeNumber, void* msg){ std::promise* prom = reinterpret_cast*>(p); try { throwIfError(excTypeNumber, msg); } catch (const matlab::engine::MATLABSyntaxException& ex) { prom->set_exception(std::make_exception_ptr(ex)); } catch (const matlab::engine::MATLABExecutionException& ex) { prom->set_exception(std::make_exception_ptr(ex)); } catch (const matlab::engine::CancelledException& ex) { prom->set_exception(std::make_exception_ptr(ex)); } catch (const matlab::engine::InterruptedException& ex) { prom->set_exception(std::make_exception_ptr(ex)); } catch (const matlab::engine::MATLABException& ex) { prom->set_exception(std::make_exception_ptr(ex)); } catch (const std::exception& ex) { prom->set_exception(std::make_exception_ptr(ex)); } delete prom; } inline void set_eval_promise_data(void *p) { std::promise* prom = reinterpret_cast*>(p); prom->set_value(); delete prom; } inline void set_eval_promise_exception(void *p, int excTypeNumber, void* msg) { std::promise* prom = reinterpret_cast*>(p); try { throwIfError(excTypeNumber, msg); } catch (const matlab::engine::MATLABSyntaxException& ex) { prom->set_exception(std::make_exception_ptr(ex)); } catch (const matlab::engine::MATLABExecutionException& ex) { prom->set_exception(std::make_exception_ptr(ex)); } catch (const matlab::engine::CancelledException& ex) { prom->set_exception(std::make_exception_ptr(ex)); } catch (const matlab::engine::InterruptedException& ex) { prom->set_exception(std::make_exception_ptr(ex)); } catch (const matlab::engine::MATLABException& ex) { prom->set_exception(std::make_exception_ptr(ex)); } catch (const std::exception& ex) { prom->set_exception(std::make_exception_ptr(ex)); } delete prom; } inline void set_feval_promise_data(void *p, int nlhs, bool straight, matlab::data::impl::ArrayImpl** plhs) { if (nlhs == 0 && straight) { std::promise* prom = reinterpret_cast*>(p); prom->set_value(); delete prom; return; } if (nlhs == 1 && straight) { std::promise* prom = reinterpret_cast*>(p); matlab::data::Array v_ = matlab::data::detail::Access::createObj(plhs[0]); prom->set_value(v_); delete prom; return; } std::promise >* prom = reinterpret_cast >*>(p); std::vector result; for (int i = 0; i < nlhs; i++) { matlab::data::Array v_ = matlab::data::detail::Access::createObj(plhs[i]); result.push_back(v_); } prom->set_value(result); delete prom; } template void set_exception(T p, std::exception_ptr e) { p->set_exception(e); } inline void set_feval_promise_exception(void *p, int nlhs, bool straight, int excTypeNumber, void* msg) { if (nlhs == 0 && straight) { set_promise_exception(p, excTypeNumber, msg); } else if (nlhs == 1 && straight) { set_promise_exception(p, excTypeNumber, msg); } else { set_promise_exception>(p, excTypeNumber, msg); } } } matlab::engine::FutureResult> matlab::engine::MATLABEngine::fevalAsync(const std::u16string &function, const int nlhs, const std::vector &args, const std::shared_ptr &output, const std::shared_ptr &error) { int nrhs = static_cast(args.size()); matlab::data::impl::ArrayImpl** args_arr_impl = (nrhs == 0) ? nullptr : (matlab::data::impl::ArrayImpl**) malloc(sizeof(matlab::data::impl::ArrayImpl*) * nrhs); std::unique_ptr args_impl_guard(args_arr_impl, &implDeleter); void** args_impl = reinterpret_cast(args_arr_impl); arrayToImpl(nrhs, args_impl, args); std::promise >* p = new std::promise >(); std::future > f = p->get_future(); std::string function_utf8 = matlab::engine::convertUTF16StringToUTF8String(function); void* output_ = output ? new std::shared_ptr(std::move(output)) : nullptr; void* error_ = error ? new std::shared_ptr(std::move(error)) : nullptr; uintptr_t handle = mexApiFevalAsync(pImpl, nlhs, nrhs, args_impl, function_utf8.c_str(), false, &set_feval_promise_data, &set_feval_promise_exception, p, output_, error_, &writeToStreamBuffer, &deleteStreamBufferImpl); return matlab::engine::FutureResult>(std::move(f), std::make_shared(handle, mexApiCancelFevalWithCompletion)); } matlab::engine::FutureResult> matlab::engine::MATLABEngine::fevalAsync(const std::string &function, const int nlhs, const std::vector &args, const std::shared_ptr &output, const std::shared_ptr &error) { return fevalAsync(std::u16string(function.begin(), function.end()), nlhs, args, output, error); } matlab::engine::FutureResult matlab::engine::MATLABEngine::fevalAsync(const std::u16string &function, const std::vector &args, const std::shared_ptr &output, const std::shared_ptr &error) { int nrhs = static_cast(args.size()); matlab::data::impl::ArrayImpl** args_arr_impl = (nrhs == 0) ? nullptr : (matlab::data::impl::ArrayImpl**) malloc(sizeof(matlab::data::impl::ArrayImpl*) * nrhs); std::unique_ptr args_impl_guard(args_arr_impl, &implDeleter); void** args_impl = reinterpret_cast(args_arr_impl); arrayToImpl(nrhs, args_impl, args); std::promise* p = new std::promise(); std::future f = p->get_future(); std::string function_utf8 = matlab::engine::convertUTF16StringToUTF8String(function); void* output_ = output ? new std::shared_ptr(std::move(output)) : nullptr; void* error_ = error ? new std::shared_ptr(std::move(error)) : nullptr; uintptr_t handle = mexApiFevalAsync(pImpl, 1, nrhs, args_impl, function_utf8.c_str(), true, &set_feval_promise_data, &set_feval_promise_exception, p, output_, error_, &writeToStreamBuffer, &deleteStreamBufferImpl); return matlab::engine::FutureResult(std::move(f), std::make_shared(handle, mexApiCancelFevalWithCompletion)); } matlab::engine::FutureResult matlab::engine::MATLABEngine::fevalAsync(const std::string &function, const std::vector &args, const std::shared_ptr &output, const std::shared_ptr &error) { return fevalAsync(std::u16string(function.begin(), function.end()), args, output, error); } matlab::engine::FutureResult matlab::engine::MATLABEngine::fevalAsync(const std::u16string &function, const matlab::data::Array &arg, const std::shared_ptr &output, const std::shared_ptr &error) { return fevalAsync(function, std::vector({ arg }), output, error); } matlab::engine::FutureResult matlab::engine::MATLABEngine::fevalAsync(const std::string &function, const matlab::data::Array &arg, const std::shared_ptr &output, const std::shared_ptr &error) { return fevalAsync(std::u16string(function.begin(), function.end()), arg, output, error); } template matlab::engine::FutureResult matlab::engine::MATLABEngine::fevalAsync(const std::u16string &function, const std::shared_ptr &output, const std::shared_ptr &error, RhsArgs&&... rhsArgs) { matlab::data::ArrayFactory factory; std::vector rhsList({ detail::createRhs(factory, std::forward(rhsArgs))... }); auto const nlhs = detail::createLhs::nlhs; size_t nrhs = rhsList.size(); matlab::data::impl::ArrayImpl** argsImpl = new matlab::data::impl::ArrayImpl*[nrhs]; size_t i = 0; for (auto e : rhsList) { argsImpl[i++] = matlab::data::detail::Access::getImpl(e); } matlab::engine::FutureResult> f = fevalAsync(function, nlhs, rhsList, output, error); // c++11 lambdas do not correctly handle move operations... // when c++14 is available, this should be: // auto convertToResultType = [copyableF = std::move(f)]()->ReturnType { ....... }; auto copyableF = std::make_shared>>(std::move(f)); auto convertToResultType = [copyableF]() ->ReturnType { std::vector vec = copyableF->get(); detail::createLhs lhsFactory; return lhsFactory(std::move(vec)); }; std::future future = std::async(std::launch::deferred, std::move(convertToResultType)); return matlab::engine::FutureResult(std::move(future), copyableF->getTaskReference()); } template matlab::engine::FutureResult matlab::engine::MATLABEngine::fevalAsync(const std::string &function, const std::shared_ptr &output, const std::shared_ptr &error, RhsArgs&&... rhsArgs) { return fevalAsync(std::u16string(function.begin(), function.end()), output, error, std::forward(rhsArgs)...); } template matlab::engine::FutureResult matlab::engine::MATLABEngine::fevalAsync(const std::u16string &function, RhsArgs&&... rhsArgs) { const std::shared_ptr defaultStream; return fevalAsync(function, defaultStream, defaultStream, std::forward(rhsArgs)...); } template matlab::engine::FutureResult matlab::engine::MATLABEngine::fevalAsync(const std::string &function, RhsArgs&&... rhsArgs) { return fevalAsync(std::u16string(function.begin(), function.end()), std::forward(rhsArgs)...); } matlab::engine::FutureResult matlab::engine::MATLABEngine::evalAsync(const std::u16string &str, const std::shared_ptr &output, const std::shared_ptr &error) { std::promise* p = new std::promise(); std::future f = p->get_future(); void* output_ = output ? new std::shared_ptr(std::move(output)) : nullptr; void* error_ = error ? new std::shared_ptr(std::move(error)) : nullptr; uintptr_t handle = mexApiEvalAsync(pImpl, str.c_str(), &set_eval_promise_data, &set_eval_promise_exception, p, output_, error_, &writeToStreamBuffer, &deleteStreamBufferImpl); return matlab::engine::FutureResult(std::move(f), std::make_shared(handle, mexApiCancelFevalWithCompletion)); } matlab::engine::FutureResult matlab::engine::MATLABEngine::getVariableAsync(const std::u16string &varName, WorkspaceType workspaceType) { std::promise* p = new std::promise(); std::future f = p->get_future(); const char* workspace = (workspaceType == matlab::engine::WorkspaceType::BASE) ? "base" : "global"; uintptr_t handle = mexApiGetVariableAsync(pImpl, workspace, varName.c_str(), &set_feval_promise_data, &set_feval_promise_exception, p); return matlab::engine::FutureResult(std::move(f), std::make_shared(handle, mexApiCancelFevalWithCompletion)); } matlab::engine::FutureResult matlab::engine::MATLABEngine::getVariableAsync(const std::string &varName, WorkspaceType workspaceType) { return getVariableAsync(std::u16string(varName.begin(), varName.end()), workspaceType); } matlab::engine::FutureResult matlab::engine::MATLABEngine::setVariableAsync(const std::u16string &varName, const matlab::data::Array &var, WorkspaceType workspaceType) { std::promise* p = new std::promise(); std::future f = p->get_future(); const char* workspace = (workspaceType == matlab::engine::WorkspaceType::BASE) ? "base" : "global"; matlab::data::impl::ArrayImpl* varImpl = matlab::data::detail::Access::getImpl(var); uintptr_t handle = mexApiSetVariableAsync(pImpl, varImpl, workspace, varName.c_str(), &set_feval_promise_data, &set_feval_promise_exception, p); return matlab::engine::FutureResult(std::move(f), std::make_shared(handle, mexApiCancelFevalWithCompletion)); } matlab::engine::FutureResult matlab::engine::MATLABEngine::setVariableAsync(const std::string &varName, const matlab::data::Array &var, WorkspaceType workspaceType) { return setVariableAsync(std::u16string(varName.begin(), varName.end()), var, workspaceType); } matlab::engine::FutureResult matlab::engine::MATLABEngine::getPropertyAsync(const matlab::data::Array &object, size_t index, const std::u16string &propertyName) { std::promise* p = new std::promise(); std::future f = p->get_future(); matlab::data::impl::ArrayImpl* objectImpl = matlab::data::detail::Access::getImpl(object); uintptr_t handle = mexApiGetPropertyAsync(pImpl, objectImpl, index, propertyName.c_str(), &set_feval_promise_data, &set_feval_promise_exception, p); return matlab::engine::FutureResult(std::move(f), std::make_shared(handle, mexApiCancelFevalWithCompletion)); } matlab::engine::FutureResult matlab::engine::MATLABEngine::getPropertyAsync(const matlab::data::Array &object, size_t index, const std::string &propertyName) { return getPropertyAsync(object, index, std::u16string(propertyName.begin(), propertyName.end())); } matlab::engine::FutureResult matlab::engine::MATLABEngine::getPropertyAsync(const matlab::data::Array &object, const std::u16string &propertyName) { return getPropertyAsync(object, 0, propertyName); } matlab::engine::FutureResult matlab::engine::MATLABEngine::getPropertyAsync(const matlab::data::Array &object, const std::string &propertyName) { return getPropertyAsync(object, std::u16string(propertyName.begin(), propertyName.end())); } matlab::engine::FutureResult matlab::engine::MATLABEngine::setPropertyAsync(matlab::data::Array &object, size_t index, const std::u16string &propertyName, const matlab::data::Array &value) { std::promise* p = new std::promise(); std::future f = p->get_future(); matlab::data::impl::ArrayImpl* objectImpl = matlab::data::detail::Access::getImpl(object); matlab::data::impl::ArrayImpl* propImpl = matlab::data::detail::Access::getImpl(value); uintptr_t handle = mexApiSetPropertyAsync(pImpl, objectImpl, index, propertyName.c_str(), propImpl, &set_feval_promise_data, &set_feval_promise_exception, p); auto copyableF = std::make_shared>(std::move(f)); auto convertToResultType = [&object, copyableF]() { matlab::data::Array vec = copyableF->get(); object = std::move(vec); }; std::future future = std::async(std::launch::deferred, std::move(convertToResultType)); return FutureResult(std::move(future), std::make_shared(handle, mexApiCancelFevalWithCompletion)); } matlab::engine::FutureResult matlab::engine::MATLABEngine::setPropertyAsync(matlab::data::Array &object, size_t index, const std::string &propertyName, const matlab::data::Array &value) { return setPropertyAsync(object, index, std::u16string(propertyName.begin(), propertyName.end()), value); } matlab::engine::FutureResult matlab::engine::MATLABEngine::setPropertyAsync(matlab::data::Array &object, const std::u16string &propertyName, const matlab::data::Array &value) { return setPropertyAsync(object, 0, propertyName, value); } matlab::engine::FutureResult matlab::engine::MATLABEngine::setPropertyAsync(matlab::data::Array &object, const std::string &propertyName, const matlab::data::Array &value) { return setPropertyAsync(object, std::u16string(propertyName.begin(), propertyName.end()), value); } #endif