|
#include "mex.h" |
|
#include <string> |
|
#include <map> |
|
#include <memory> |
|
using namespace std; |
|
|
|
#define LOCKING |
|
#define ATEXIT |
|
|
|
#ifdef _WIN32 |
|
#include <windows.h> |
|
BOOL APIENTRY DllMain(HANDLE hModule, DWORD dwReason, LPVOID lpReserved) |
|
{ |
|
switch (dwReason) { |
|
case DLL_PROCESS_ATTACH: |
|
mexPrintf("-- DLL_PROCESS_ATTACH: hModule=0x%x\n", hModule); |
|
break; |
|
case DLL_THREAD_ATTACH: |
|
case DLL_THREAD_DETACH: |
|
break; |
|
case DLL_PROCESS_DETACH: |
|
mexPrintf("-- DLL_PROCESS_DETACH: hModule=0x%x\n", hModule); |
|
break; |
|
} |
|
return TRUE; |
|
} |
|
#endif |
|
|
|
// fake cv::Ptr with C++11 smart pointers |
|
#define Ptr std::shared_ptr |
|
#define makePtr std::make_shared |
|
|
|
class MyClass |
|
{ |
|
public: |
|
MyClass(int x = 0) : id(x) { mexPrintf("[C] MyClass ctor id=%d\n", id); } |
|
~MyClass() { mexPrintf("[C] MyClass dtor id=%d\n", id); } |
|
void call() { mexPrintf("[C] MyClass call id=%d\n", id); } |
|
int get() { return id; } |
|
void set(int x) { id = x; } |
|
private: |
|
int id; |
|
}; |
|
|
|
namespace { |
|
int last_id = 0; |
|
map<int,Ptr<MyClass>> obj_; |
|
} |
|
|
|
static void onExit() |
|
{ |
|
mexPrintf("[C] MEX atexit. size(map)=%d\n", obj_.size()); |
|
#ifdef ATEXIT |
|
// because we use lock/unlock, this is not really needed |
|
obj_.clear(); |
|
#endif |
|
} |
|
|
|
static void nargchk(bool cond) |
|
{ |
|
if (!cond) |
|
mexErrMsgIdAndTxt("mex:error", "wrong number of args"); |
|
} |
|
|
|
static string toString(const mxArray* p) |
|
{ |
|
if (!mxIsChar(p)) |
|
mexErrMsgIdAndTxt("mex:error", "not a string"); |
|
char *pc = mxArrayToString(p); |
|
string str(pc); |
|
mxFree(pc); |
|
return str; |
|
} |
|
|
|
static int toInt(const mxArray *p) |
|
{ |
|
if (!mxIsDouble(p) || mxGetNumberOfElements(p)!=1) |
|
mexErrMsgIdAndTxt("mex:error", "not an int"); |
|
return static_cast<int>(*(mxGetPr(p))); |
|
} |
|
|
|
static mxArray* fromInt(int x) |
|
{ |
|
return mxCreateDoubleScalar(x); |
|
} |
|
|
|
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) |
|
{ |
|
mexAtExit(onExit); |
|
|
|
nargchk(nrhs>=2 && nlhs<=1); |
|
int id = toInt(prhs[0]); |
|
string method = toString(prhs[1]); |
|
mexPrintf("[C] MEX begin id=%d\n", id); |
|
|
|
if (method == "new") { |
|
nargchk((nrhs==2||nrhs==3) && nlhs<=1); |
|
obj_[++last_id] = makePtr<MyClass>((nrhs==3) ? toInt(prhs[0]) : last_id); |
|
#ifdef LOCKING |
|
mexLock(); mexPrintf("-- lock\n"); |
|
#endif |
|
plhs[0] = fromInt(last_id); |
|
return; |
|
} |
|
|
|
#if 1 |
|
Ptr<MyClass> obj = obj_[id]; |
|
if (!obj) mexWarnMsgIdAndTxt("mex:error", "invalid id=%d", id); |
|
#else |
|
auto it = obj_.find(id); |
|
if (it == obj_.end()) { |
|
// we should not throw errors inside MATLAB class destructors |
|
if (method == "delete") |
|
mexWarnMsgIdAndTxt("mex:warn", "invalid id=%d", id); |
|
else |
|
mexErrMsgIdAndTxt("mex:error", "invalid id=%d", id); |
|
return; |
|
} |
|
Ptr<MyClass> obj = it->second; |
|
#endif |
|
|
|
if (method == "delete") { |
|
obj_.erase(id); |
|
#ifdef LOCKING |
|
mexUnlock(); mexPrintf("-- unlock\n"); |
|
#endif |
|
} |
|
else if (method == "load") { |
|
obj_[id] = makePtr<MyClass>(99); |
|
} |
|
else if (method == "call") { |
|
obj->call(); |
|
} |
|
else if (method == "get") { |
|
plhs[0] = fromInt(obj->get()); |
|
} |
|
else if (method == "set") { |
|
obj->set(toInt(prhs[2])); |
|
} |
|
|
|
mexPrintf("[C] MEX end %d\n", id); |
|
} |