-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit e1cf778
Showing
8 changed files
with
302 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
*.asv | ||
*~ | ||
*.mex* | ||
.DS_Store |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
#ifndef __CLASS_HANDLE_HPP__ | ||
#define __CLASS_HANDLE_HPP__ | ||
#include "mex.h" | ||
#include <stdint.h> | ||
#include <string> | ||
#include <cstring> | ||
#include <typeinfo> | ||
|
||
#define CLASS_HANDLE_SIGNATURE 0xFF00F0A5 | ||
template<class base> class class_handle | ||
{ | ||
public: | ||
class_handle(base *ptr) : signature_m(CLASS_HANDLE_SIGNATURE), name_m(typeid(base).name()), ptr_m(ptr) {} | ||
~class_handle() { signature_m = 0; delete ptr_m; } | ||
bool isValid() { return ((signature_m == CLASS_HANDLE_SIGNATURE) && !strcmp(name_m.c_str(), typeid(base).name())); } | ||
base* ptr() { return ptr_m; } | ||
|
||
private: | ||
uint32_t signature_m; | ||
const std::string name_m; | ||
base* const ptr_m; | ||
}; | ||
|
||
template<class base> inline mxArray *convertPtr2Mat(base *ptr) | ||
{ | ||
mexLock(); | ||
mxArray *out = mxCreateNumericMatrix(1, 1, mxUINT64_CLASS, mxREAL); | ||
*((uint64_t *)mxGetData(out)) = reinterpret_cast<uint64_t>(new class_handle<base>(ptr)); | ||
return out; | ||
} | ||
|
||
template<class base> inline class_handle<base> *convertMat2HandlePtr(const mxArray *in) | ||
{ | ||
if (mxGetNumberOfElements(in) != 1 || mxGetClassID(in) != mxUINT64_CLASS || mxIsComplex(in)) | ||
mexErrMsgTxt("Input must be a real uint64 scalar."); | ||
class_handle<base> *ptr = reinterpret_cast<class_handle<base> *>(*((uint64_t *)mxGetData(in))); | ||
if (!ptr->isValid()) | ||
mexErrMsgTxt("Handle not valid."); | ||
return ptr; | ||
} | ||
|
||
template<class base> inline base *convertMat2Ptr(const mxArray *in) | ||
{ | ||
return convertMat2HandlePtr<base>(in)->ptr(); | ||
} | ||
|
||
template<class base> inline void destroyObject(const mxArray *in) | ||
{ | ||
delete convertMat2HandlePtr<base>(in); | ||
mexUnlock(); | ||
} | ||
|
||
#endif // __CLASS_HANDLE_HPP__ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
%EXAMPLE_INTERFACE Example MATLAB class wrapper to an underlying C++ class | ||
classdef example_interface < handle | ||
properties (SetAccess = private, Hidden = true) | ||
objectHandle; % Handle to the underlying C++ class instance | ||
end | ||
methods | ||
%% Constructor - Create a new C++ class instance | ||
function this = example_interface(varargin) | ||
this.objectHandle = example_mex('new', varargin{:}); | ||
end | ||
|
||
%% Destructor - Destroy the C++ class instance | ||
function delete(this) | ||
example_mex('delete', this.objectHandle); | ||
end | ||
|
||
%% Train - an example class method call | ||
function varargout = train(this, varargin) | ||
[varargout{1:nargout}] = example_mex('train', this.objectHandle, varargin{:}); | ||
end | ||
|
||
%% Test - another example class method call | ||
function varargout = test(this, varargin) | ||
[varargout{1:nargout}] = example_mex('test', this.objectHandle, varargin{:}); | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
#include "mex.h" | ||
#include "class_handle.hpp" | ||
|
||
// The class that we are interfacing to | ||
class example | ||
{ | ||
public: | ||
example() { mexPrintf("Calling constructor\n"); } | ||
~example() { mexPrintf("Calling destructor\n"); } | ||
void train() { mexPrintf("Calling train\n"); }; | ||
void test() { mexPrintf("Calling test\n"); }; | ||
private: | ||
}; | ||
|
||
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) | ||
{ | ||
// Get the command string | ||
char cmd[64]; | ||
if (nrhs < 1 || mxGetString(prhs[0], cmd, sizeof(cmd))) | ||
mexErrMsgTxt("First input should be a command string less than 64 characters long."); | ||
|
||
// New | ||
if (!strcmp("new", cmd)) { | ||
// Check parameters | ||
if (nlhs != 1) | ||
mexErrMsgTxt("New: One output expected."); | ||
// Return a handle to a new C++ instance | ||
plhs[0] = convertPtr2Mat<example>(new example); | ||
return; | ||
} | ||
|
||
// Check there is a second input, which should be the class instance handle | ||
if (nrhs < 2) | ||
mexErrMsgTxt("Second input should be a class instance handle."); | ||
|
||
// Delete | ||
if (!strcmp("delete", cmd)) { | ||
// Destroy the C++ object | ||
destroyObject<example>(prhs[1]); | ||
// Warn if other commands were ignored | ||
if (nlhs != 0 || nrhs != 2) | ||
mexWarnMsgTxt("Delete: Unexpected arguments ignored."); | ||
return; | ||
} | ||
|
||
// Get the class instance pointer from the second input | ||
example* example_instance = convertMat2Ptr<example>(prhs[1]); | ||
|
||
// Call the various class methods | ||
// Train | ||
if (!strcmp("train", cmd)) { | ||
// Check parameters | ||
if (nlhs < 0 || nrhs < 2) | ||
mexErrMsgTxt("Train: Unexpected arguments."); | ||
// Call the method | ||
example_instance->train(); | ||
return; | ||
} | ||
// Test | ||
if (!strcmp("test", cmd)) { | ||
// Check parameters | ||
if (nlhs < 0 || nrhs < 2) | ||
mexErrMsgTxt("Test: Unexpected arguments."); | ||
// Call the method | ||
example_instance->test(); | ||
return; | ||
} | ||
|
||
// Got here, so command not recognized | ||
mexErrMsgTxt("Command not recognized."); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
Copyright (c) 2018, Oliver Woodford | ||
All rights reserved. | ||
|
||
Redistribution and use in source and binary forms, with or without | ||
modification, are permitted provided that the following conditions are | ||
met: | ||
|
||
* Redistributions of source code must retain the above copyright | ||
notice, this list of conditions and the following disclaimer. | ||
* Redistributions in binary form must reproduce the above copyright | ||
notice, this list of conditions and the following disclaimer in | ||
the documentation and/or other materials provided with the distribution | ||
|
||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | ||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | ||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | ||
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE | ||
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | ||
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | ||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | ||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | ||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | ||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | ||
POSSIBILITY OF SUCH DAMAGE. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
%MEX_INTERFACE MATLAB wrapper to an underlying C++ class | ||
% | ||
% This interface assumes that the mex function uses the following standard | ||
% interface: | ||
% Construction - obj = mexfun('new', ...) | ||
% Destruction - mexfun('delete', obj) | ||
% Other methods - [...] = mexfun('method', obj, ...) | ||
classdef mex_interface < handle | ||
properties (Access = private, Hidden = true) | ||
objectHandle; % Handle to the underlying C++ class instance | ||
mexHandle; % Handle to the mex function | ||
end | ||
methods | ||
%% Constructor - Create a new C++ class instance | ||
% Inputs: | ||
% mexfun - handle to the C++ class interface mex. | ||
% varargin - arguments passed to the mex when calling 'new'. | ||
function this = mex_interface(mexfun, varargin) | ||
this.mexHandle = mexfun; | ||
this.objectHandle = this.mexHandle('new', varargin{:}); | ||
end | ||
|
||
%% Destructor - Destroy the C++ class instance | ||
function delete(this) | ||
if ~isempty(this.objectHandle) | ||
this.mexHandle('delete', this.objectHandle); | ||
end | ||
this.objectHandle = []; | ||
end | ||
|
||
%% Disp - get the function name | ||
function disp(this, var_name) | ||
if nargin > 1 | ||
fprintf('%s is an object instance of %s\n', var_name, func2str(this.mexHandle)); | ||
else | ||
fprintf('Object instance of %s\n', func2str(this.mexHandle)); | ||
end | ||
end | ||
|
||
%% All other methods | ||
function varargout = subsref(this, s) | ||
if numel(s) < 2 || ~isequal(s(1).type, '.') || ~isequal(s(2).type, '()') | ||
error('Not a valid indexing expression') | ||
end | ||
assert(~isempty(this.objectHandle), 'Object not initialized correctly'); | ||
[varargout{1:nargout}] = this.mexHandle(s(1).subs, this.objectHandle, s(2).subs{:}); | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
function run_example() | ||
% Check if the mex exists | ||
dir = fileparts(mfilename('fullpath')); | ||
if ~isequal(fileparts(which('example_mex')), dir) | ||
% Compile the mex | ||
cwd = cd(dir); | ||
cleanup_obj = onCleanup(@() cd(cwd)); | ||
fprintf('Compiling example_mex\n'); | ||
mex example_mex.cpp | ||
end | ||
|
||
% Use the example interface | ||
% This is the interface written specifically for the example class | ||
fprintf('Using the example interface\n'); | ||
obj = example_interface(); | ||
train(obj); | ||
test(obj); | ||
clear obj % Clear calls the delete method | ||
|
||
% Use the standard interface | ||
% This interface can be used for any mex interface function using the | ||
% pattern: | ||
% Construction - obj = mexfun('new', ...) | ||
% Destruction - mexfun('delete', obj) | ||
% Other methods - [...] = mexfun('method', obj, ...) | ||
% The standard interface avoids the need to write a specific interface | ||
% class for each mex file. | ||
fprintf('Using the standard interface\n'); | ||
obj = mex_interface(str2fun([dir '/example_mex'])); % str2fun allows us to use the full path, so the mex need not be on our path | ||
obj.train(); | ||
obj.test(); | ||
clear obj % Clear calls the delete method | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
%STR2FUN Construct a function_handle from a function name or path. | ||
% FUNHANDLE = STR2FUN(S) constructs a function_handle FUNHANDLE to the | ||
% function named in the character vector S. The S input must be a | ||
% character vector. The S input cannot be a character array with | ||
% multiple rows or a cell array of character vectors. | ||
% | ||
% You can create a function handle using either the @function syntax or | ||
% the STR2FUN command. You can create an array of function handles from | ||
% character vectors by creating the handles individually with STR2FUN, | ||
% and then storing these handles in a cell array. | ||
% | ||
% Examples: | ||
% | ||
% To create a function handle from the function name, 'humps': | ||
% | ||
% fhandle = str2func('humps') | ||
% fhandle = | ||
% @humps | ||
% | ||
% To call STR2FUNC on a cell array of character vectors, use the | ||
% CELLFUN function. This returns a cell array of function handles: | ||
% | ||
% fh_array = cellfun(@str2func, {'sin' 'cos' 'tan'}, ... | ||
% 'UniformOutput', false); | ||
% fh_array{2}(5) | ||
% ans = | ||
% 0.2837 | ||
% | ||
% See also STR2FUNC, FUNCTION_HANDLE, FUNC2STR, FUNCTIONS. | ||
|
||
function fun = str2fun(str) | ||
assert(ischar(str)); | ||
if str(1) ~= '@' | ||
[p, str] = fileparts(str); | ||
if ~isempty(p) | ||
cwd = cd(p); | ||
cleanup_obj = onCleanup(@() cd(cwd)); | ||
end | ||
end | ||
fun = str2func(str); | ||
end |