From da639198116520f45f2d4ab57f1ec076714d3462 Mon Sep 17 00:00:00 2001 From: hbristow Date: Mon, 24 Jun 2013 12:42:28 -0700 Subject: [PATCH] Improved error handling on entry to mex files --- .../templates/template_function_base.cpp | 8 +- modules/matlab/include/bridge.hpp | 87 +++++++++++++++---- 2 files changed, 76 insertions(+), 19 deletions(-) diff --git a/modules/matlab/generator/templates/template_function_base.cpp b/modules/matlab/generator/templates/template_function_base.cpp index 2539ed3633..053f27debb 100644 --- a/modules/matlab/generator/templates/template_function_base.cpp +++ b/modules/matlab/generator/templates/template_function_base.cpp @@ -12,6 +12,7 @@ #include "bridge.hpp" #include #include +#include #include #include using namespace cv; @@ -29,9 +30,10 @@ void mexFunction(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[]) { // assertions - mxAssert(nrhs >= {{fun.req|length - fun.req|outputs|length}}, "Too few required input arguments specified"); - mxAssert(nrhs <= {{fun.req|length + fun.opt|length - fun.req|outputs|length - fun.opt|outputs|length}}, "Too many input arguments specified"); - mxAssert(nlhs <= {{ fun.rtp|void|not + fun.req|outputs|length + fun.opt|outputs|length}}, "Too many output arguments specified"); + mexPrintf("nrhs: %d, nlhs: %d\n", nrhs, nlhs); + conditionalError(nrhs >= {{fun.req|length - fun.req|outputs|length}}, "Too few required input arguments specified"); + conditionalError(nrhs <= {{fun.req|length + fun.opt|length - fun.req|outputs|length - fun.opt|outputs|length}}, "Too many input arguments specified"); + conditionalError(nlhs <= {{ fun.rtp|void|not + fun.req|outputs|length + fun.opt|outputs|length}}, "Too many output arguments specified"); // setup std::vector inputs(plhs, plhs+nrhs); diff --git a/modules/matlab/include/bridge.hpp b/modules/matlab/include/bridge.hpp index 23a430d8f3..37f2dd6eb3 100644 --- a/modules/matlab/include/bridge.hpp +++ b/modules/matlab/include/bridge.hpp @@ -4,6 +4,7 @@ #include "mex.h" #include #include +#include /* * Custom typedefs @@ -13,6 +14,11 @@ typedef std::vector vector_Mat; typedef std::vector vector_Point; typedef std::vector vector_int; + +void conditionalError(bool expr, const std::string& str) { + if (!expr) mexErrMsgTxt(std::string("condition failed: ").append(str).c_str()); +} + /*! * @class Bridge * @brief Type conversion class for converting OpenCV and native C++ types @@ -50,11 +56,52 @@ typedef std::vector vector_int; * */ class Bridge { +private: + mxArray* ptr_; public: // bridges are default constructible Bridge() {} virtual ~Bridge() {} + /*! @brief unpack an object from Matlab into C++ + * + * this function checks whether the given bridge is derived from an + * object in Matlab. If so, it converts it to a (platform dependent) + * pointer to the underlying C++ object. + * + * NOTE! This function assumes that the C++ pointer is stored in inst_ + */ + template + Object* getObjectByName(const char* name) { + // check that the object is actually of correct type before unpacking + // TODO: Traverse class hierarchy? + if (!mxIsClass(ptr_, name)) { + const char* actual = mxGetClassName(ptr_); + mexErrMsgTxt(std::string("Expected class ").append(std::string(name)) + .append(" but was given ").append(std::string(actual)).c_str()); + } + // get the instance field + mxArray* inst = mxGetField(ptr_, 0, "inst_"); + Object* obj = NULL; + // make sure the pointer is the correct size for the system + if (sizeof(void *) == 8 && mxIsClass(inst, "uint64")) { + // 64-bit pointers + // TODO: Do we REALLY REALLY need to reinterpret_cast? + obj = reinterpret_cast( + reinterpret_cast(mxGetData(inst))[0]); + } else if (sizeof(void *) == 4 && mxIsClass(inst, "uint32")) { + // 32-bit pointers + obj = reinterpret_cast( + reinterpret_cast(mxGetData(inst))[0]); + } else { + mexErrMsgTxt("Incorrect pointer type stored for architecture"); + } + + // finally check if the object is NULL + if (!obj) mexErrMsgTxt(std::string("Object ").append(std::string(name)).append(std::string(" is NULL")).c_str()); + return obj; + } + // --------------------------- mxArray -------------------------------------- Bridge& operator=(const mxArray* obj) { return *this; } Bridge(const mxArray* obj) {} @@ -62,78 +109,86 @@ public: // --------------------------- cv::Mat -------------------------------------- Bridge& operator=(const cv::Mat& obj) { return *this; } - operator cv::Mat() { return cv::Mat(); } cv::Mat toMat() { return cv::Mat(); } + operator cv::Mat() { return toMat(); } // -------------------- vector_Mat -------------------------------- Bridge& operator=(const vector_Mat& obj) { return *this; } - operator vector_Mat() { return vector_Mat(); } vector_Mat toVectorMat() { return vector_Mat(); } + operator vector_Mat() { return toVectorMat(); } // --------------------------- int -------------------------------------- Bridge& operator=(const int& obj) { return *this; } - operator int() { return 0; } int toInt() { return 0; } + operator int() { return toInt(); } // --------------------------- vector_int ---------------------------------- Bridge& operator=(const vector_int& obj) { return *this; } - operator vector_int() { return vector_int(); } vector_int toVectorInt() { return vector_int(); } + operator vector_int() { return toVectorInt(); } // --------------------------- string -------------------------------------- Bridge& operator=(const std::string& obj) { return *this; } - operator std::string() { return ""; } std::string toString() { return ""; } + operator std::string() { return toString(); } // --------------------------- bool -------------------------------------- Bridge& operator=(const bool& obj) { return *this; } - operator bool() { return 0; } bool toBool() { return 0; } + operator bool() { return toBool(); } // --------------------------- double -------------------------------------- Bridge& operator=(const double& obj) { return *this; } - operator double() { return 0; } double toDouble() { return 0; } + operator double() { return toDouble(); } // -------------------------- Point -------------------------------------- Bridge& operator=(const cv::Point& obj) { return *this; } - operator cv::Point() { return cv::Point(); } cv::Point toPoint() { return cv::Point(); } + operator cv::Point() { return toPoint(); } // -------------------------- Size --------------------------------------- Bridge& operator=(const cv::Size& obj) { return *this; } - operator cv::Size() { return cv::Size(); } cv::Size toSize() { return cv::Size(); } + operator cv::Size() { return toSize(); } // ------------------------ vector_Point ------------------------------------ Bridge& operator=(const vector_Point& obj) { return *this; } - operator vector_Point() { return vector_Point(); } vector_Point toVectorPoint() { return vector_Point(); } + operator vector_Point() { return toVectorPoint(); } // -------------------------- Scalar -------------------------------------- Bridge& operator=(const cv::Scalar& obj) { return *this; } - operator cv::Scalar() { return cv::Scalar(); } cv::Scalar toScalar() { return cv::Scalar(); } + operator cv::Scalar() { return toScalar(); } // -------------------------- Rect -------------------------------------- Bridge& operator=(const cv::Rect& obj) { return *this; } - operator cv::Rect() { return cv::Rect(); } cv::Rect toRect() { return cv::Rect(); } + operator cv::Rect() { return toRect(); } // ---------------------- RotatedRect ------------------------------------ Bridge& operator=(const cv::RotatedRect& obj) { return *this; } - operator cv::RotatedRect() { return cv::RotatedRect(); } cv::RotatedRect toRotatedRect() { return cv::RotatedRect(); } + operator cv::RotatedRect() { return toRotatedRect(); } // ---------------------- TermCriteria ----------------------------------- Bridge& operator=(const cv::TermCriteria& obj) { return *this; } - operator cv::TermCriteria() { return cv::TermCriteria(); } cv::TermCriteria toTermCriteria() { return cv::TermCriteria(); } + operator cv::TermCriteria() { return toTermCriteria(); } // ---------------------- RNG ----------------------------------- Bridge& operator=(const cv::RNG& obj) { return *this; } - operator cv::RNG() { return cv::RNG(); } - cv::RNG toRNG() { return cv::RNG(); } + /*! @brief explicit conversion to cv::RNG() + * + * Converts a bridge object to a cv::RNG(). We explicitly assert that + * the object is an RNG in matlab space before attempting to deference + * its pointer + */ + cv::RNG toRNG() { + return (*getObjectByName("RNG")); + } + operator cv::RNG() { return toRNG(); } };