diff --git a/gtsam.h b/gtsam.h index f5d245111..2c2e41e66 100644 --- a/gtsam.h +++ b/gtsam.h @@ -64,7 +64,18 @@ namespace gtsam { // base //************************************************************************* -class LieVector { +class Value { + // Testable + void print(string s) const; + bool equals(const gtsam::Value& expected, double tol) const; + + // Manifold + size_t dim() const; + gtsam::Value retract(Vector v) const; + Vector localCoordinates(const gtsam::Value& t2) const; +}; + +class LieVector : gtsam::Value { // Standard constructors LieVector(); LieVector(Vector v); diff --git a/wrap/Argument.cpp b/wrap/Argument.cpp index 40ad205b6..35f20169b 100644 --- a/wrap/Argument.cpp +++ b/wrap/Argument.cpp @@ -64,7 +64,7 @@ void Argument::matlab_unwrap(FileWriter& file, const string& matlabName) const { file.oss << cppType << " " << name << " = unwrap< "; file.oss << cppType << " >(" << matlabName; - if (is_ptr || is_ref) file.oss << ", \"" << matlabType << "\""; + if (is_ptr || is_ref) file.oss << ", \"ptr_" << matlabType << "\""; file.oss << ");" << endl; } diff --git a/wrap/Class.cpp b/wrap/Class.cpp index a33f89f35..2688f625e 100644 --- a/wrap/Class.cpp +++ b/wrap/Class.cpp @@ -39,9 +39,11 @@ void Class::matlab_proxy(const string& classFile, const string& wrapperName, Fil // emit class proxy code // we want our class to inherit the handle class for memory purposes - proxyFile.oss << "classdef " << matlabName << " < handle" << endl; + const string parent = qualifiedParent.empty() ? + "handle" : ::wrap::qualifiedName("", qualifiedParent); + proxyFile.oss << "classdef " << matlabName << " < " << parent << endl; proxyFile.oss << " properties" << endl; - proxyFile.oss << " self = 0" << endl; + proxyFile.oss << " ptr_" << matlabName << " = 0" << endl; proxyFile.oss << " end" << endl; proxyFile.oss << " methods" << endl; @@ -116,10 +118,7 @@ void Class::matlab_proxy(const string& classFile, const string& wrapperName, Fil /* ************************************************************************* */ string Class::qualifiedName(const string& delim) const { - string result; - BOOST_FOREACH(const string& ns, namespaces) - result += ns + delim; - return result + name; + return ::wrap::qualifiedName(delim, namespaces, name); } /* ************************************************************************* */ @@ -136,14 +135,14 @@ string Class::pointer_constructor_fragments(FileWriter& proxyFile, FileWriter& w (uint64_t('r')); const string matlabName = qualifiedName(), cppName = qualifiedName("::"); - const string wrapFunctionName = matlabName + "_constructor_" + boost::lexical_cast(id); + const string wrapFunctionName = matlabName + "_collectorInsert_" + boost::lexical_cast(id); // MATLAB constructor that assigns pointer to matlab object then calls c++ // function to add the object to the collector. proxyFile.oss << " if nargin == 2 && isa(varargin{1}, 'uint64') && "; proxyFile.oss << "varargin{1} == uint64(" << ptr_constructor_key << ")\n"; proxyFile.oss << " obj.self = varargin{2};\n"; - proxyFile.oss << " " << wrapperName << "(obj.self);\n"; + proxyFile.oss << " " << wrapperName << "(" << id << ", obj.self);\n"; // C++ function to add pointer from MATLAB to collector. The pointer always // comes from a C++ return value; this mechanism allows the object to be added diff --git a/wrap/Class.h b/wrap/Class.h index f1a745d94..4d31b4972 100644 --- a/wrap/Class.h +++ b/wrap/Class.h @@ -38,6 +38,7 @@ struct Class { // Then the instance variables are set directly by the Module constructor std::string name; ///< Class name + std::vector qualifiedParent; ///< The *single* parent - the last string is the parent class name, preceededing elements are a namespace stack Methods methods; ///< Class methods StaticMethods static_methods; ///< Static methods std::vector namespaces; ///< Stack of namespaces diff --git a/wrap/Constructor.cpp b/wrap/Constructor.cpp index 88fbb748b..63ea15146 100644 --- a/wrap/Constructor.cpp +++ b/wrap/Constructor.cpp @@ -53,7 +53,7 @@ void Constructor::proxy_fragment(FileWriter& file, const std::string& wrapperNam file.oss << "\n obj.self = " << wrapperName << "(" << id; // emit constructor arguments for(size_t i=0;i& using_namespaces, vector& functionNames) const { - proxyFile.oss << " function varargout = " << name << "(self, varargin)\n"; + proxyFile.oss << " function varargout = " << name << "(this, varargin)\n"; for(size_t overload = 0; overload < argLists.size(); ++overload) { const ArgumentList& args = argLists[overload]; @@ -74,7 +74,7 @@ void Method::proxy_wrapper_fragments(FileWriter& proxyFile, FileWriter& wrapperF output = ""; else output = "varargout{1} = "; - proxyFile.oss << " " << output << wrapperName << "(" << id << ", self, varargin{:});\n"; + proxyFile.oss << " " << output << wrapperName << "(" << id << ", this, varargin{:});\n"; // Output C++ wrapper code @@ -135,7 +135,7 @@ string Method::wrapper_fragment(FileWriter& file, // get class pointer // example: shared_ptr = unwrap_shared_ptr< Test >(in[0], "Test"); - file.oss << " Shared obj = unwrap_shared_ptr<" << cppClassName << ">(in[0], \"" << cppClassName << "\");" << endl; + file.oss << " Shared obj = unwrap_shared_ptr<" << cppClassName << ">(in[0], \"ptr_" << matlabClassName << "\");" << endl; // unwrap arguments, see Argument.cpp args.matlab_unwrap(file,1); diff --git a/wrap/Module.cpp b/wrap/Module.cpp index 86cc90ef1..5482a19b1 100644 --- a/wrap/Module.cpp +++ b/wrap/Module.cpp @@ -93,7 +93,7 @@ Module::Module(const string& interfacePath, Rule eigenType_p = (str_p("Vector") | "Matrix"); - Rule className_p = (lexeme_d[upper_p >> *(alnum_p | '_')] - eigenType_p - keywords_p)[assign_a(class_name)]; + Rule className_p = (lexeme_d[upper_p >> *(alnum_p | '_')] - eigenType_p - keywords_p); Rule namespace_name_p = lexeme_d[lower_p >> *(alnum_p | '_')] - keywords_p; @@ -114,6 +114,10 @@ Module::Module(const string& interfacePath, className_p[assign_a(arg.type)] >> (ch_p('*')[assign_a(arg.is_ptr,true)] | ch_p('&')[assign_a(arg.is_ref,true)]); + Rule classParent_p = + *(namespace_name_p[push_back_a(cls.qualifiedParent)] >> str_p("::")) >> + className_p[push_back_a(cls.qualifiedParent)]; + Rule name_p = lexeme_d[alpha_p >> *(alnum_p | '_')]; Rule argument_p = @@ -198,7 +202,7 @@ Module::Module(const string& interfacePath, (!*include_p >> str_p("class")[push_back_a(cls.includes, include_path)][assign_a(include_path, null_str)] >> className_p[assign_a(cls.name)] - >> '{' + >> ((':' >> classParent_p >> '{') | '{') // By having (parent >> '{' | '{') here instead of (!parent >> '{'), we trigger a parse error on a badly-formed parent spec >> *(functions_p | comments_p) >> str_p("};")) [assign_a(constructor.name, cls.name)] diff --git a/wrap/matlab.h b/wrap/matlab.h index 31778cdbd..90f706a37 100644 --- a/wrap/matlab.h +++ b/wrap/matlab.h @@ -342,9 +342,14 @@ gtsam::Matrix unwrap< gtsam::Matrix >(const mxArray* array) { [create_object] creates a MATLAB proxy class object with a mexhandle in the self property. Matlab does not allow the creation of matlab objects from within mex files, hence we resort to an ugly trick: we - invoke the proxy class constructor by calling MATLAB, and pass 13 - dummy arguments to let the constructor know we want an object without - the self property initialized. We then assign the mexhandle to self. + invoke the proxy class constructor by calling MATLAB with a special + uint64 value ptr_constructor_key and the pointer itself. MATLAB + allocates the object. Then, the special constructor in our wrap code + that is activated when the ptr_constructor_key is passed in passes + the pointer back into a C++ function to add the pointer to its + collector. We go through this extra "C++ to MATLAB to C++ step" in + order to be able to add to the collector could be in a different wrap + module. */ mxArray* create_object(const char *classname, void *pointer) { mxArray *result; @@ -376,9 +381,9 @@ mxArray* wrap_shared_ptr(boost::shared_ptr< Class >* shared_ptr, const char *cla } template -boost::shared_ptr unwrap_shared_ptr(const mxArray* obj, const string& className) { +boost::shared_ptr unwrap_shared_ptr(const mxArray* obj, const string& propertyName) { - mxArray* mxh = mxGetProperty(obj,0,"self"); + mxArray* mxh = mxGetProperty(obj,0, propertyName); if (mxGetClassID(mxh) != mxUINT32OR64_CLASS || mxIsComplex(mxh) || mxGetM(mxh) != 1 || mxGetN(mxh) != 1) error( "Parameter is not an Shared type."); diff --git a/wrap/utilities.cpp b/wrap/utilities.cpp index 31b65bdcc..fdad6de7c 100644 --- a/wrap/utilities.cpp +++ b/wrap/utilities.cpp @@ -135,6 +135,17 @@ void generateIncludes(FileWriter& file, const string& class_name, } /* ************************************************************************* */ +string qualifiedName(const string& separator, const vector& names, const string& finalName) { + string result; + for(size_t i = 0; i < names.size() - 1; ++i) + result += (names[i] + separator); + if(finalName.empty()) + result += names.back(); + else + result += (names.back() + separator + finalName); + return result; +} +/* ************************************************************************* */ } // \namespace wrap diff --git a/wrap/utilities.h b/wrap/utilities.h index 1eb0e249f..6652cc8fd 100644 --- a/wrap/utilities.h +++ b/wrap/utilities.h @@ -98,4 +98,10 @@ void generateUsingNamespace(FileWriter& file, const std::vector& us void generateIncludes(FileWriter& file, const std::string& class_name, const std::vector& includes); +/** + * Return a qualified name, if finalName is empty, only the names vector will + * be used (i.e. there won't be a trailing separator on the qualified name). + */ +std::string qualifiedName(const std::string& separator, const std::vector& names, const std::string& finalName = ""); + } // \namespace wrap