diff --git a/modules/matlab/include/opencv2/matlab/bridge.hpp b/modules/matlab/include/opencv2/matlab/bridge.hpp index 624305de9c..4b0ed29c60 100644 --- a/modules/matlab/include/opencv2/matlab/bridge.hpp +++ b/modules/matlab/include/opencv2/matlab/bridge.hpp @@ -165,7 +165,9 @@ public: // MATLAB TYPES // -------------------------------------------------------------------------- Bridge& operator=(const mxArray* obj) { ptr_ = obj; return *this; } - Bridge(const mxArray* obj) : ptr_(obj) {} + Bridge& operator=(const MxArray& obj) { ptr_ = obj; return *this; } + Bridge(const MxArray& obj) : ptr_(obj) {} + Bridge(const mxArray* obj) : ptr_(obj) {} MxArray toMxArray() { return ptr_; } diff --git a/modules/matlab/include/opencv2/matlab/mxarray.hpp b/modules/matlab/include/opencv2/matlab/mxarray.hpp index 584832458a..fe0f82f393 100644 --- a/modules/matlab/include/opencv2/matlab/mxarray.hpp +++ b/modules/matlab/include/opencv2/matlab/mxarray.hpp @@ -49,6 +49,8 @@ #include #include #include +#include +#include #include #if __cplusplus > 201103 #include @@ -533,6 +535,7 @@ private: typedef std::vector IndexVector; typedef std::vector MxArrayVector; typedef std::vector VariantVector; + /* @class Variant * @brief Describes a variant of arguments to a method * @@ -542,43 +545,79 @@ private: * inputs for a method invocation. */ class Variant { + private: + String name_; + size_t Nreq_; + size_t Nopt_; + StringVector keys_; + IndexVector order_; + bool valid_; + size_t nparsed_; + size_t nkeys_; + size_t working_opt_; + bool expecting_val_; + bool using_named_; + size_t find(const String& key) const { + return std::find(keys_.begin(), keys_.end(), key) - keys_.begin(); + } public: - Variant(const String& _name, size_t _nreq, size_t _nopt, const StringVector& _keys) - : name(_name), nreq(_nreq), nopt(_nopt), keys(_keys), using_named(false) {} - String name; - size_t nreq; - size_t nopt; - StringVector keys; - IndexVector order; - bool using_named; - /*! @brief return true if the named-argument is in the Variant */ - bool count(const String& key) { return std::find(keys.begin(), keys.end(), key) != keys.end(); } - /*! @brief remove a key by index from the Variant */ - void erase(const size_t idx) { keys.erase(keys.begin()+idx); } - /*! @brief remove a key by name from the Variant */ - void erase(const String& key) { keys.erase(std::find(keys.begin(), keys.end(), key)); } - /*! @brief convert a Variant to a string representation */ - String toString(const String& method_name=String("f")) const { + /*! @brief default constructor */ + Variant() : Nreq_(0), Nopt_(0), valid_(false) {} + /*! @brief construct a new variant spec */ + Variant(const String& name, size_t Nreq, size_t Nopt, const StringVector& keys) + : name_(name), Nreq_(Nreq), Nopt_(Nopt), keys_(keys), + order_(Nreq+Nopt, Nreq+2*Nopt), valid_(true), nparsed_(0), nkeys_(0), + working_opt_(0), expecting_val_(false), using_named_(false) {} + /*! @brief return the total number of arguments the variant can take */ + size_t size() const { return Nreq_ + Nopt_; } + /*! @brief has the variant been fulfilled? */ + bool fulfilled() const { return (valid_ && nparsed_ >= Nreq_ && !expecting_val_); } + /*! @brief is the variant in a valid state (though not necessarily fulfilled) */ + bool valid() const { return valid_; } + /*! @brief check if the named argument exists in the variant */ + bool exist(const String& key) const { return find(key) != keys_.size(); } + /*! @brief retrieve the order mapping raw inputs to their position in the variant */ + const IndexVector& order() const { return order_; } + size_t order(size_t n) const { return order_[n]; } + /*! @brief attempt to parse the next argument as a value */ + bool parseNextAsValue() { + if (!valid_) {} + else if ((using_named_ && !expecting_val_) || (nparsed_-nkeys_ == Nreq_+Nopt_)) { valid_ = false; } + else if (nparsed_ < Nreq_) { order_[nparsed_] = nparsed_; } + else if (!using_named_) { order_[nparsed_] = nparsed_; } + else if (using_named_ && expecting_val_) { order_[Nreq_ + working_opt_] = nparsed_; } + nparsed_++; + expecting_val_ = false; + return valid_; + } + /*! @biref attempt to parse the next argument as a name (key) */ + bool parseNextAsKey(const String& key) { + if (!valid_) {} + else if ((nparsed_ < Nreq_) || (nparsed_-nkeys_ == Nreq_+Nopt_)) { valid_ = false; } + else if (using_named_ && expecting_val_) { valid_ = false; } + else if ((working_opt_ = find(key)) == keys_.size()) { valid_ = false; } + else { using_named_ = true; expecting_val_ = true; nkeys_++; nparsed_++; } + return valid_; + } + String toString(const String& method_name="f") const { std::ostringstream s; s << method_name << "("; - for (size_t n = 0; n < nreq; ++n) { - s << "src" << n+1; if (n != nreq-1) s << ", "; - } - if (nreq && nopt) s << ", "; - for (size_t n = 0; n < keys.size(); ++n) { - s << "'" << keys[n] << "', " << keys[n]; - if (n != keys.size()-1) s << ", "; - } + for (size_t n = 0; n < Nreq_; ++n) { s << "src" << n+1 << (n != Nreq_-1 ? ", " : ""); } + if (Nreq_ && Nopt_) s << ", "; + for (size_t n = 0; n < keys_.size(); ++n) { s << "'" << keys_[n] << "', " << keys_[n] << (n != Nopt_-1 ? ", " : ""); } s << ");"; return s.str(); } }; + /*! @brief given an input and output vector of arguments, and a variant spec, sort */ void sortArguments(Variant& v, MxArrayVector& in, MxArrayVector& out) { // allocate the output array with ALL arguments - out.resize(v.nreq + v.nopt); + out.resize(v.size()); + std::copy(v.order().begin(), v.order().end(), std::ostream_iterator(std::cout, ", ")); // reorder the inputs based on the variant ordering - for (size_t n = 0; n < v.order.size(); ++n) { - swap(in[n], out[v.order[n]]); + for (size_t n = 0; n < v.size(); ++n) { + if (v.order(n) >= in.size()) continue; + swap(in[v.order(n)], out[n]); } } MxArrayVector filled_; @@ -587,6 +626,7 @@ private: String method_name_; public: ArgumentParser(const String& method_name) : method_name_(method_name) {} + /*! @brief add a function call variant to the parser * * Adds a function-call signature to the parser. The function call *must* be @@ -606,10 +646,12 @@ public: void addVariant(const String& name, size_t nreq, size_t nopt, StringVector keys) { variants_.push_back(Variant(name, nreq, nopt, keys)); } + /*! @brief check if the valid variant is the key name */ bool variantIs(const String& name) { return name.compare(valid_) == 0; } + /*! @brief parse a vector of input arguments * * This method parses a vector of input arguments, attempting to match them @@ -633,51 +675,19 @@ public: for (MxArrayVector::const_iterator input = inputs.begin(); input != inputs.end(); ++input) { String name = input->isString() ? input->toString() : String(); for (VariantVector::iterator candidate = candidates.begin(); candidate < candidates.end(); ++candidate) { - // check if the input is a key - bool key = candidate->count(name); - - /* - * FAILURE CASES - * 1. too many inputs, or - * 2. name is not a key and we're expecting a key - * 3. name is a key, and - * we're still expecting required arguments, or - * we're expecting an argument for a previous key - */ - if ((!candidate->nreq && !candidate->nopt) || - (!key && !candidate->nreq && candidate->keys.size() == candidate->nopt && candidate->using_named) || - (key && (candidate->nreq || candidate->keys.size() < candidate->nopt))) { - candidate = candidates.erase(candidate)--; - } - - // VALID CASES - // Still parsing required argments (input is not a key) - else if (!key && candidate->nreq) { - candidate->nreq--; - } - - // Parsing optional arguments and a named argument is encountered - else if (key && !candidate->nreq && candidate->nopt > 0 && candidate->keys.size() == candidate->nopt) { - candidate->erase(name); - candidate->using_named = true; - } - - // Parsing input for a named argument - else if (!key && candidate->keys.size() < candidate->nopt) { - candidate->nopt--; - } - - // Parsing un-named optional arguments - else if (!key && !candidate->nreq && candidate->nopt && candidate->keys.size() && !candidate->using_named) { - candidate->erase(0); - candidate->nopt--; + if (candidate->exist(name)) { + mexPrintf("%d\n", candidate->parseNextAsKey(name)); + } else { + mexPrintf("%d\n", candidate->parseNextAsValue()); } } } - // if any candidates remain, check that they have been fully parsed + mexPrintf("We get here!\n"); + + // make sure the candidates have been fulfilled for (VariantVector::iterator candidate = candidates.begin(); candidate < candidates.end(); ++candidate) { - if (candidate->nreq || candidate->keys.size() < candidate->nopt) { + if (!candidate->fulfilled()) { candidate = candidates.erase(candidate)--; } } @@ -697,6 +707,8 @@ public: error(String("No matching method signatures for given arguments. Valid variants are:").append(variant_string)); } + // Unique candidate! + sortArguments(candidates[0], const_cast(inputs), outputs); return outputs; } };