diff options
author | Mark Spruiell <mes@zeroc.com> | 2017-09-04 14:40:47 -0700 |
---|---|---|
committer | Mark Spruiell <mes@zeroc.com> | 2017-09-04 14:40:47 -0700 |
commit | cdfd2cbb48cccc460541d21f604834975fe05720 (patch) | |
tree | 6e1277a7ecbe091098ae4e2c8e3c87c44799f7ad /matlab/src/IceMatlab/Util.cpp | |
parent | Fix PHP build warnings (diff) | |
download | ice-cdfd2cbb48cccc460541d21f604834975fe05720.tar.bz2 ice-cdfd2cbb48cccc460541d21f604834975fe05720.tar.xz ice-cdfd2cbb48cccc460541d21f604834975fe05720.zip |
Initial commit of MATLAB prototype
Diffstat (limited to 'matlab/src/IceMatlab/Util.cpp')
-rw-r--r-- | matlab/src/IceMatlab/Util.cpp | 648 |
1 files changed, 648 insertions, 0 deletions
diff --git a/matlab/src/IceMatlab/Util.cpp b/matlab/src/IceMatlab/Util.cpp new file mode 100644 index 00000000000..d4c15b7255e --- /dev/null +++ b/matlab/src/IceMatlab/Util.cpp @@ -0,0 +1,648 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2017 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +#include <Ice/LocalException.h> +#include <iostream> +#include <string> +#include <locale> +#include <codecvt> +#include "icematlab.h" +#include "Util.h" + +using namespace std; + +namespace +{ + +string +replace(string s, string patt, string val) +{ + string r = s; + string::size_type pos = r.find(patt); + while(pos != string::npos) + { + r.replace(pos, patt.size(), val); + pos += val.size(); + pos = r.find(patt, pos); + } + return r; +} + +void +getMajorMinor(mxArray* p, Ice::Byte& major, Ice::Byte& minor) +{ + mxArray* maj = mxGetProperty(p, 0, "major"); + assert(maj); + if(!mxIsScalar(maj)) + { + throw std::invalid_argument("major is not a scalar"); + } + major = static_cast<Ice::Byte>(mxGetScalar(maj)); + mxArray* min = mxGetProperty(p, 0, "minor"); + assert(min); + if(!mxIsScalar(min)) + { + throw std::invalid_argument("minor is not a scalar"); + } + minor = static_cast<Ice::Byte>(mxGetScalar(min)); +} + +} + +mxArray* +IceMatlab::createStringFromUTF8(const string& s) +{ +#ifdef _MSC_VER + // + // Workaround for Visual Studio bug that causes a link error when using char16_t. + // + wstring utf16 = wstring_convert<codecvt_utf8_utf16<wchar_t>, wchar_t>{}.from_bytes(s.data()); +#else + u16string utf16 = wstring_convert<codecvt_utf8_utf16<char16_t>, char16_t>{}.from_bytes(s.data()); +#endif + mwSize dims[2] = { 1, utf16.size() }; + mxArray* r = mxCreateCharArray(2, dims); + mxChar* buf = mxGetChars(r); + int i = 0; +#ifdef _MSC_VER + for(wchar_t c : utf16) +#else + for(char16_t c : utf16) +#endif + { + buf[i++] = static_cast<mxChar>(c); + } + return r; +} + +string +IceMatlab::getStringFromUTF16(mxArray* p) +{ + char* s = mxArrayToUTF8String(p); + if(!s) + { + throw std::invalid_argument("value is not a char array"); + } + string str(s); + mxFree(s); + return str; +} + +mxArray* +IceMatlab::createEmpty() +{ + return mxCreateNumericMatrix(0, 0, mxDOUBLE_CLASS, mxREAL); +} + +mxArray* +IceMatlab::createBool(bool v) +{ + mxArray* r = mxCreateNumericMatrix(1, 1, mxLOGICAL_CLASS, mxREAL); + bool* p = reinterpret_cast<bool*>(mxGetPr(r)); + *p = v; + return r; +} + +mxArray* +IceMatlab::createByte(Ice::Byte v) +{ + mxArray* r = mxCreateNumericMatrix(1, 1, mxUINT8_CLASS, mxREAL); + Ice::Byte* p = reinterpret_cast<Ice::Byte*>(mxGetPr(r)); + *p = v; + return r; +} + +mxArray* +IceMatlab::createShort(short v) +{ + mxArray* r = mxCreateNumericMatrix(1, 1, mxINT16_CLASS, mxREAL); + short* p = reinterpret_cast<short*>(mxGetPr(r)); + *p = v; + return r; +} + +mxArray* +IceMatlab::createInt(int v) +{ + mxArray* r = mxCreateNumericMatrix(1, 1, mxINT32_CLASS, mxREAL); + int* p = reinterpret_cast<int*>(mxGetPr(r)); + *p = v; + return r; +} + +mxArray* +IceMatlab::createLong(long long v) +{ + mxArray* r = mxCreateNumericMatrix(1, 1, mxINT64_CLASS, mxREAL); + long long* p = reinterpret_cast<long long*>(mxGetPr(r)); + *p = v; + return r; +} + +mxArray* +IceMatlab::createFloat(float v) +{ + mxArray* r = mxCreateNumericMatrix(1, 1, mxSINGLE_CLASS, mxREAL); + float* p = reinterpret_cast<float*>(mxGetPr(r)); + *p = v; + return r; +} + +mxArray* +IceMatlab::createDouble(double v) +{ + mxArray* r = mxCreateNumericMatrix(1, 1, mxDOUBLE_CLASS, mxREAL); + double* p = reinterpret_cast<double*>(mxGetPr(r)); + *p = v; + return r; +} + +mxArray* +IceMatlab::createEnumerator(const string& type, int v) +{ + string func = type + ".ice_getValue"; + mxArray* param = createInt(v); + mxArray* r; + mexCallMATLAB(1, &r, 1, ¶m, func.c_str()); + mxFree(param); + return r; +} + +int +IceMatlab::getEnumerator(mxArray* p, const string& type) +{ + if(!mxIsClass(p, type.c_str())) + { + throw invalid_argument("expected enumerator of type " + type); + } + return static_cast<int>(mxGetScalar(p)); +} + +mxArray* +IceMatlab::createIdentity(const Ice::Identity& id) +{ + mxArray* params[2]; + params[0] = createStringFromUTF8(id.name); + params[1] = createStringFromUTF8(id.category); + mxArray* r; + mexCallMATLAB(1, &r, 2, params, "Ice.Identity"); + return r; +} + +void +IceMatlab::getIdentity(mxArray* p, Ice::Identity& id) +{ + if(!mxIsClass(p, "Ice.Identity")) + { + throw std::invalid_argument("argument is not Ice.Identity"); + } + mxArray* name = mxGetProperty(p, 0, "name"); + assert(name); + id.name = getStringFromUTF16(name); + mxArray* category = mxGetProperty(p, 0, "category"); + assert(category); + id.category = getStringFromUTF16(category); +} + +mxArray* +IceMatlab::createStringMap(const map<string, string>& m) +{ + mxArray* r; + if(m.empty()) + { + mexCallMATLAB(1, &r, 0, 0, "containers.Map"); + } + else + { + mwSize dims[2] = {1, 0}; + dims[1] = m.size(); + mxArray* keys = mxCreateCellArray(2, dims); + mxArray* values = mxCreateCellArray(2, dims); + int idx = 0; + for(map<string, string>::const_iterator p = m.begin(); p != m.end(); ++p) + { + mxSetCell(keys, idx, createStringFromUTF8(p->first)); + mxSetCell(values, idx, createStringFromUTF8(p->second)); + idx++; + } + mxArray* params[2]; + params[0] = keys; + params[1] = values; + mexCallMATLAB(1, &r, 2, params, "containers.Map"); + } + return r; +} + +void +IceMatlab::getStringMap(mxArray* p, map<string, string>& m) +{ + if(mxIsEmpty(p)) + { + m.clear(); + } + else if(!mxIsClass(p, "containers.Map")) + { + throw std::invalid_argument("argument is not a containers.Map"); + } + else + { + mxArray* params[1]; + params[0] = p; + mxArray* keys; + mexCallMATLAB(1, &keys, 1, params, "keys"); + mxArray* values; + mexCallMATLAB(1, &values, 1, params, "values"); + assert(mxGetM(keys) == 1 && mxGetM(values) == 1); + assert(mxGetN(keys) == mxGetN(values)); + const size_t n = mxGetN(keys); + try + { + for(size_t i = 0; i < n; ++i) + { + string k = getStringFromUTF16(mxGetCell(keys, i)); + string v = getStringFromUTF16(mxGetCell(values, i)); + m[k] = v; + } + mxDestroyArray(keys); + mxDestroyArray(values); + } + catch(...) + { + mxDestroyArray(keys); + mxDestroyArray(values); + throw; + } + } +} + +mxArray* +IceMatlab::createEncodingVersion(const Ice::EncodingVersion& v) +{ + mxArray* params[2]; + params[0] = mxCreateDoubleScalar(v.major); + params[1] = mxCreateDoubleScalar(v.minor); + mxArray* r; + mexCallMATLAB(1, &r, 2, params, "Ice.EncodingVersion"); + return r; +} + +void +IceMatlab::getEncodingVersion(mxArray* p, Ice::EncodingVersion& v) +{ + if(!mxIsClass(p, "Ice.EncodingVersion")) + { + throw std::invalid_argument("argument is not Ice.EncodingVersion"); + } + getMajorMinor(p, v.major, v.minor); +} + +mxArray* +IceMatlab::createProtocolVersion(const Ice::ProtocolVersion& v) +{ + mxArray* params[2]; + params[0] = mxCreateDoubleScalar(v.major); + params[1] = mxCreateDoubleScalar(v.minor); + mxArray* r; + mexCallMATLAB(1, &r, 2, params, "Ice.ProtocolVersion"); + return r; +} + +void +IceMatlab::getProtocolVersion(mxArray* p, Ice::ProtocolVersion& v) +{ + if(!mxIsClass(p, "Ice.ProtocolVersion")) + { + throw std::invalid_argument("argument is not Ice.ProtocolVersion"); + } + getMajorMinor(p, v.major, v.minor); +} + +mxArray* +IceMatlab::convertException(const std::exception& exc) +{ + mxArray* ex; + if(dynamic_cast<const Ice::LocalException*>(&exc)) + { + const Ice::LocalException* iceEx = dynamic_cast<const Ice::LocalException*>(&exc); + const string typeId = iceEx->ice_id(); + // + // The exception ID uses single colon separators. + // + string id = typeId.substr(2); // Remove leading "::" from type ID + id = replace(id, "::", ":"); + + string cls = typeId.substr(2); // Remove leading "::" from type ID + cls = replace(cls, "::", "."); + + mxArray* params[10]; + params[0] = createStringFromUTF8(id); + int idx = 2; + string msg = typeId; // Use the type ID as the default exception message + + try + { + iceEx->ice_throw(); + } + catch(const Ice::InitializationException& e) + { + msg = e.reason; + params[idx++] = createStringFromUTF8(e.reason); + } + catch(const Ice::PluginInitializationException& e) + { + msg = e.reason; + params[idx++] = createStringFromUTF8(e.reason); + } + catch(const Ice::AlreadyRegisteredException& e) + { + params[idx++] = createStringFromUTF8(e.kindOfObject); + params[idx++] = createStringFromUTF8(e.id); + } + catch(const Ice::NotRegisteredException& e) + { + params[idx++] = createStringFromUTF8(e.kindOfObject); + params[idx++] = createStringFromUTF8(e.id); + } + catch(const Ice::TwowayOnlyException& e) + { + params[idx++] = createStringFromUTF8(e.operation); + } + catch(const Ice::UnknownException& e) + { + params[idx++] = createStringFromUTF8(e.unknown); + } + catch(const Ice::ObjectAdapterDeactivatedException& e) + { + params[idx++] = createStringFromUTF8(e.name); + } + catch(const Ice::ObjectAdapterIdInUseException& e) + { + params[idx++] = createStringFromUTF8(e.id); + } + catch(const Ice::NoEndpointException& e) + { + params[idx++] = createStringFromUTF8(e.proxy); + } + catch(const Ice::EndpointParseException& e) + { + params[idx++] = createStringFromUTF8(e.str); + } + catch(const Ice::EndpointSelectionTypeParseException& e) + { + params[idx++] = createStringFromUTF8(e.str); + } + catch(const Ice::VersionParseException& e) + { + params[idx++] = createStringFromUTF8(e.str); + } + catch(const Ice::IdentityParseException& e) + { + params[idx++] = createStringFromUTF8(e.str); + } + catch(const Ice::ProxyParseException& e) + { + params[idx++] = createStringFromUTF8(e.str); + } + catch(const Ice::IllegalIdentityException& e) + { + params[idx++] = createIdentity(e.id); + } + catch(const Ice::RequestFailedException& e) + { + params[idx++] = createIdentity(e.id); + params[idx++] = createStringFromUTF8(e.facet); + params[idx++] = createStringFromUTF8(e.operation); + } + catch(const Ice::FileException& e) + { + params[idx++] = mxCreateDoubleScalar(e.error); + params[idx++] = createStringFromUTF8(e.path); + } + catch(const Ice::SyscallException& e) // This must appear after all subclasses of SyscallException. + { + params[idx++] = mxCreateDoubleScalar(e.error); + } + catch(const Ice::DNSException& e) + { + params[idx++] = mxCreateDoubleScalar(e.error); + params[idx++] = createStringFromUTF8(e.host); + } + catch(const Ice::UnsupportedProtocolException& e) + { + params[idx++] = createProtocolVersion(e.bad); + params[idx++] = createProtocolVersion(e.supported); + } + catch(const Ice::UnsupportedEncodingException& e) + { + params[idx++] = createEncodingVersion(e.bad); + params[idx++] = createEncodingVersion(e.supported); + } + catch(const Ice::ConnectionManuallyClosedException& e) + { + params[idx++] = mxCreateLogicalScalar(e.graceful ? 1 : 0); + } + catch(const Ice::NoValueFactoryException& e) + { + params[idx++] = createStringFromUTF8(e.reason); + params[idx++] = createStringFromUTF8(e.type); + } + catch(const Ice::UnexpectedObjectException& e) + { + params[idx++] = createStringFromUTF8(e.reason); + params[idx++] = createStringFromUTF8(e.type); + params[idx++] = createStringFromUTF8(e.expectedType); + } + catch(const Ice::ProtocolException& e) // This must appear after all subclasses of ProtocolException. + { + params[idx++] = createStringFromUTF8(e.reason); + } + catch(const Ice::FeatureNotSupportedException& e) + { + params[idx++] = createStringFromUTF8(e.unsupportedFeature); + } + catch(const Ice::SecurityException& e) + { + params[idx++] = createStringFromUTF8(e.reason); + } + catch(const Ice::IllegalServantException& e) + { + params[idx++] = createStringFromUTF8(e.reason); + } + catch(const Ice::LocalException&) + { + // + // Nothing to do. + // + } + + // + // NOTE: Matlab interprets the msg argument as an sprintf format string. It will complain if it + // finds invalid syntax. + // + params[1] = createStringFromUTF8(msg); + mexCallMATLAB(1, &ex, idx, params, cls.c_str()); + } + else + { + mxArray* params[2]; + params[0] = createStringFromUTF8("Ice:CppException"); + params[1] = createStringFromUTF8(exc.what()); + mexCallMATLAB(1, &ex, 2, params, "MException"); + } + return ex; +} + +static const char* resultFields[] = {"exception", "result"}; + +mxArray* +IceMatlab::createResultValue(mxArray* result) +{ + mwSize dims[2] = {1, 1}; + mxArray* r = mxCreateStructArray(2, dims, 2, resultFields); + mxSetFieldByNumber(r, 0, 1, result); + return r; +} + +mxArray* +IceMatlab::createResultException(mxArray* ex) +{ + mwSize dims[2] = {1, 1}; + mxArray* r = mxCreateStructArray(2, dims, 2, resultFields); + mxSetFieldByNumber(r, 0, 0, ex); + return r; +} + +mxArray* +IceMatlab::createStringList(const vector<string>& v) +{ + mxArray* r = mxCreateCellMatrix(1, v.size()); + mwIndex i = 0; + for(vector<string>::const_iterator p = v.begin(); p != v.end(); ++p, ++i) + { + mxSetCell(r, i, createStringFromUTF8(*p)); + } + return r; +} + +void +IceMatlab::getStringList(mxArray* m, vector<string>& v) +{ + if(!mxIsCell(m)) + { + throw std::invalid_argument("argument is not a cell array"); + } + if(mxGetM(m) > 1) + { + throw std::invalid_argument("invalid dimension in cell array"); + } + size_t n = mxGetN(m); + v.clear(); + for(size_t i = 0; i < n; ++i) + { + mxArray* c = mxGetCell(m, i); + v.push_back(getStringFromUTF16(c)); + } +} + +#if 0 +void* +IceMatlab::getImpl(mxArray* obj, const std::string& className) +{ + void* p = 0; + if(!mxIsEmpty(obj)) + { + if(!mxIsClass(obj, className.c_str())) + { + throw std::invalid_argument("expecting object of type " + className); + } + mxArray* implProp = mxGetProperty(obj, 0, "impl"); + assert(implProp); + mxArray* value = mxGetProperty(implProp, 0, "value"); + assert(value); + p = mxGetData(value); + } + return p; +} +#endif + +namespace +{ + +string +lookupKwd(const string& name) +{ + // + // Keyword list. *Must* be kept in alphabetical order. + // + // This list must match the one in slice2matlab. + // + static const string keywordList[] = + { + "break", "case", "catch", "classdef", "continue", "else", "elseif", "end", "for", "function", "global", + "if", "otherwise", "parfor", "persistent", "return", "spmd", "switch", "try", "while" + }; + bool found = binary_search(&keywordList[0], + &keywordList[sizeof(keywordList) / sizeof(*keywordList)], + name); + return found ? "slice_" + name : name; +} + +// +// Split a scoped name into its components and return the components as a list of (unscoped) identifiers. +// +vector<string> +splitScopedName(const string& scoped) +{ + assert(scoped[0] == ':'); + vector<string> ids; + string::size_type next = 0; + string::size_type pos; + while((pos = scoped.find("::", next)) != string::npos) + { + pos += 2; + if(pos != scoped.size()) + { + string::size_type endpos = scoped.find("::", pos); + if(endpos != string::npos) + { + ids.push_back(scoped.substr(pos, endpos - pos)); + } + } + next = pos; + } + if(next != scoped.size()) + { + ids.push_back(scoped.substr(next)); + } + else + { + ids.push_back(""); + } + + return ids; +} + +} + +string +IceMatlab::idToClass(const string& id) +{ + vector<string> ids = splitScopedName(id); + transform(ids.begin(), ids.end(), ids.begin(), ptr_fun(lookupKwd)); + stringstream result; + for(vector<string>::const_iterator i = ids.begin(); i != ids.end(); ++i) + { + if(i != ids.begin()) + { + result << "."; + } + result << *i; + } + return result.str(); +} |