Merged from branch 'branches/wrap_mods_inheritance' into branch 'branches/wrap_mods'

release/4.3a0
Richard Roberts 2012-07-09 20:54:08 +00:00
commit 0e7b5b7832
21 changed files with 455 additions and 312 deletions

76
gtsam.h
View File

@ -14,16 +14,19 @@
* - void * - void
* - Any class with which be copied with boost::make_shared() * - Any class with which be copied with boost::make_shared()
* - boost::shared_ptr of any object type * - boost::shared_ptr of any object type
* Methods cannot return <* Constructors
* - const references of anything * - Overloads are supported
* Limitations on methods * - A class with no constructors can be returned from other functions but not allocated directly in MATLAB
* - Parsing does not support overloading * Methods
* - There can only be one method (static or otherwise) with a given name
* - Constness has no effect * - Constness has no effect
* Methods must start with a lowercase letter * - Specify by-value (not reference) return types, even if C++ method returns reference
* Static methods must start with a letter (upper or lowercase) and use the "static" keyword * - Must start with a lowercase letter
* - The function generated by wrap will start with an uppercase letter, regardless * - Overloads are supported
* Arguments to functions any of * Static methods
* - Must start with a letter (upper or lowercase) and use the "static" keyword
* - The first letter will be made uppercase in the generated MATLAB interface
* - Overloads are supported
=* Arguments to functions any of
* - Eigen types: Matrix, Vector * - Eigen types: Matrix, Vector
* - Eigen types and classes as an optionally const reference * - Eigen types and classes as an optionally const reference
* - C/C++ basic types: string, bool, size_t, size_t, double, char, unsigned char * - C/C++ basic types: string, bool, size_t, size_t, double, char, unsigned char
@ -47,15 +50,24 @@
* - All namespaces must have angle brackets: <path> * - All namespaces must have angle brackets: <path>
* - To override, add a full include statement just before the class statement * - To override, add a full include statement just before the class statement
* - An override include can be added for a namespace by placing it just before the namespace statement * - An override include can be added for a namespace by placing it just before the namespace statement
* Overriding type dependency checks * - Both classes and namespace accept exactly one namespace
* Using classes defined in other modules
* - If you are using a class 'OtherClass' not wrapped in this definition file, add "class OtherClass;" to avoid a dependency error * - If you are using a class 'OtherClass' not wrapped in this definition file, add "class OtherClass;" to avoid a dependency error
* Virtual inheritance
* - Specify fully-qualified base classes, i.e. "virtual class Derived : module::Base {"
* - Mark with 'virtual' keyword, e.g. "virtual class Base {", and also "virtual class Derived : module::Base {"
* - Forward declarations must also be marked virtual, e.g. "virtual class module::Base;" and
* also "virtual class module::Derived;"
* - Pure virtual (abstract) classes should list no constructors in this interface file
* - Virtual classes must have a clone() function in C++ (though it does not have to be included
* in the MATLAB interface). clone() will be called whenever an object copy is needed, instead
* of using the copy constructor (which is used for non-virtual objects).
*/ */
/** /**
* Status: * Status:
* - TODO: global functions * - TODO: global functions
* - TODO: default values for arguments * - TODO: default values for arguments
* - TODO: signatures for constructors can be ambiguous if two types have the same first letter
* - TODO: Handle gtsam::Rot3M conversions to quaternions * - TODO: Handle gtsam::Rot3M conversions to quaternions
*/ */
@ -65,7 +77,17 @@ namespace gtsam {
// base // base
//************************************************************************* //*************************************************************************
class LieVector { virtual class Value {
// No constructors because this is an abstract class
// Testable
void print(string s) const;
// Manifold
size_t dim() const;
};
virtual class LieVector : gtsam::Value {
// Standard constructors // Standard constructors
LieVector(); LieVector();
LieVector(Vector v); LieVector(Vector v);
@ -97,7 +119,7 @@ class LieVector {
// geometry // geometry
//************************************************************************* //*************************************************************************
class Point2 { virtual class Point2 : gtsam::Value {
// Standard Constructors // Standard Constructors
Point2(); Point2();
Point2(double x, double y); Point2(double x, double y);
@ -129,7 +151,7 @@ class Point2 {
Vector vector() const; Vector vector() const;
}; };
class StereoPoint2 { virtual class StereoPoint2 : gtsam::Value {
// Standard Constructors // Standard Constructors
StereoPoint2(); StereoPoint2();
StereoPoint2(double uL, double uR, double v); StereoPoint2(double uL, double uR, double v);
@ -158,7 +180,7 @@ class StereoPoint2 {
Vector vector() const; Vector vector() const;
}; };
class Point3 { virtual class Point3 : gtsam::Value {
// Standard Constructors // Standard Constructors
Point3(); Point3();
Point3(double x, double y, double z); Point3(double x, double y, double z);
@ -191,7 +213,7 @@ class Point3 {
double z() const; double z() const;
}; };
class Rot2 { virtual class Rot2 : gtsam::Value {
// Standard Constructors and Named Constructors // Standard Constructors and Named Constructors
Rot2(); Rot2();
Rot2(double theta); Rot2(double theta);
@ -233,7 +255,7 @@ class Rot2 {
Matrix matrix() const; Matrix matrix() const;
}; };
class Rot3 { virtual class Rot3 : gtsam::Value {
// Standard Constructors and Named Constructors // Standard Constructors and Named Constructors
Rot3(); Rot3();
Rot3(Matrix R); Rot3(Matrix R);
@ -285,7 +307,7 @@ class Rot3 {
// Vector toQuaternion() const; // FIXME: Can't cast to Vector properly // Vector toQuaternion() const; // FIXME: Can't cast to Vector properly
}; };
class Pose2 { virtual class Pose2 : gtsam::Value {
// Standard Constructor // Standard Constructor
Pose2(); Pose2();
Pose2(double x, double y, double theta); Pose2(double x, double y, double theta);
@ -331,7 +353,7 @@ class Pose2 {
Matrix matrix() const; Matrix matrix() const;
}; };
class Pose3 { virtual class Pose3 : gtsam::Value {
// Standard Constructors // Standard Constructors
Pose3(); Pose3();
Pose3(const gtsam::Pose3& pose); Pose3(const gtsam::Pose3& pose);
@ -379,7 +401,7 @@ class Pose3 {
double range(const gtsam::Pose3& pose); // FIXME: shadows other range double range(const gtsam::Pose3& pose); // FIXME: shadows other range
}; };
class Cal3_S2 { virtual class Cal3_S2 : gtsam::Value {
// Standard Constructors // Standard Constructors
Cal3_S2(); Cal3_S2();
Cal3_S2(double fx, double fy, double s, double u0, double v0); Cal3_S2(double fx, double fy, double s, double u0, double v0);
@ -429,7 +451,7 @@ class Cal3_S2Stereo {
double baseline() const; double baseline() const;
}; };
class CalibratedCamera { virtual class CalibratedCamera : gtsam::Value {
// Standard Constructors and Named Constructors // Standard Constructors and Named Constructors
CalibratedCamera(); CalibratedCamera();
CalibratedCamera(const gtsam::Pose3& pose); CalibratedCamera(const gtsam::Pose3& pose);
@ -459,7 +481,7 @@ class CalibratedCamera {
double range(const gtsam::Point3& p) const; // TODO: Other overloaded range methods double range(const gtsam::Point3& p) const; // TODO: Other overloaded range methods
}; };
class SimpleCamera { virtual class SimpleCamera : gtsam::Value {
// Standard Constructors and Named Constructors // Standard Constructors and Named Constructors
SimpleCamera(); SimpleCamera();
SimpleCamera(const gtsam::Pose3& pose); SimpleCamera(const gtsam::Pose3& pose);
@ -683,14 +705,14 @@ namespace noiseModel {
class Base { class Base {
}; };
class Gaussian { class Gaussian : gtsam::noiseModel::Base {
static gtsam::noiseModel::Gaussian* SqrtInformation(Matrix R); static gtsam::noiseModel::Gaussian* SqrtInformation(Matrix R);
static gtsam::noiseModel::Gaussian* Covariance(Matrix R); static gtsam::noiseModel::Gaussian* Covariance(Matrix R);
// Matrix R() const; // FIXME: cannot parse!!! // Matrix R() const; // FIXME: cannot parse!!!
void print(string s) const; void print(string s) const;
}; };
class Diagonal { class Diagonal : gtsam::noiseModel::Gaussian {
static gtsam::noiseModel::Diagonal* Sigmas(Vector sigmas); static gtsam::noiseModel::Diagonal* Sigmas(Vector sigmas);
static gtsam::noiseModel::Diagonal* Variances(Vector variances); static gtsam::noiseModel::Diagonal* Variances(Vector variances);
static gtsam::noiseModel::Diagonal* Precisions(Vector precisions); static gtsam::noiseModel::Diagonal* Precisions(Vector precisions);
@ -698,14 +720,14 @@ class Diagonal {
void print(string s) const; void print(string s) const;
}; };
class Isotropic { class Isotropic : gtsam::noiseModel::Gaussian {
static gtsam::noiseModel::Isotropic* Sigma(size_t dim, double sigma); static gtsam::noiseModel::Isotropic* Sigma(size_t dim, double sigma);
static gtsam::noiseModel::Isotropic* Variance(size_t dim, double varianace); static gtsam::noiseModel::Isotropic* Variance(size_t dim, double varianace);
static gtsam::noiseModel::Isotropic* Precision(size_t dim, double precision); static gtsam::noiseModel::Isotropic* Precision(size_t dim, double precision);
void print(string s) const; void print(string s) const;
}; };
class Unit { class Unit : gtsam::noiseModel::Gaussian {
static gtsam::noiseModel::Unit* Create(size_t dim); static gtsam::noiseModel::Unit* Create(size_t dim);
void print(string s) const; void print(string s) const;
}; };
@ -944,7 +966,9 @@ class Values {
Values(); Values();
size_t size() const; size_t size() const;
void print(string s) const; void print(string s) const;
void insert(size_t j, const gtsam::Value& value);
bool exists(size_t j) const; bool exists(size_t j) const;
gtsam::Value at(size_t j) const;
}; };
// Actually a FastList<Key> // Actually a FastList<Key>

View File

@ -16,7 +16,7 @@
*/ */
#pragma once #pragma once
#include <boost/make_shared.hpp>
#include <boost/pool/singleton_pool.hpp> #include <boost/pool/singleton_pool.hpp>
#include <gtsam/base/Value.h> #include <gtsam/base/Value.h>
@ -37,7 +37,8 @@ public:
/** /**
* Create a duplicate object returned as a pointer to the generic Value interface. * Create a duplicate object returned as a pointer to the generic Value interface.
* For the sake of performance, this function use singleton pool allocator instead of the normal heap allocator * For the sake of performance, this function use singleton pool allocator instead of the normal heap allocator.
* The result must be deleted with Value::deallocate_, not with the 'delete' operator.
*/ */
virtual Value* clone_() const { virtual Value* clone_() const {
void *place = boost::singleton_pool<PoolTag, sizeof(DERIVED)>::malloc(); void *place = boost::singleton_pool<PoolTag, sizeof(DERIVED)>::malloc();
@ -53,6 +54,13 @@ public:
boost::singleton_pool<PoolTag, sizeof(DERIVED)>::free((void*)this); boost::singleton_pool<PoolTag, sizeof(DERIVED)>::free((void*)this);
} }
/**
* Clone this value (normal clone on the heap, delete with 'delete' operator)
*/
virtual boost::shared_ptr<Value> clone() const {
return boost::make_shared<DERIVED>(static_cast<const DERIVED&>(*this));
}
/// equals implementing generic Value interface /// equals implementing generic Value interface
virtual bool equals_(const Value& p, double tol = 1e-9) const { virtual bool equals_(const Value& p, double tol = 1e-9) const {
// Cast the base class Value pointer to a derived class pointer // Cast the base class Value pointer to a derived class pointer

View File

@ -101,12 +101,15 @@ namespace gtsam {
class Value { class Value {
public: public:
/** Allocate and construct a clone of this value */ /** Clone this value in a special memory pool, must be deleted with Value::deallocate_, *not* with the 'delete' operator. */
virtual Value* clone_() const = 0; virtual Value* clone_() const = 0;
/** Deallocate a raw pointer of this value */ /** Deallocate a raw pointer of this value */
virtual void deallocate_() const = 0; virtual void deallocate_() const = 0;
/** Clone this value (normal clone on the heap, delete with 'delete' operator) */
virtual boost::shared_ptr<Value> clone() const = 0;
/** Compare this Value with another for equality. */ /** Compare this Value with another for equality. */
virtual bool equals_(const Value& other, double tol = 1e-9) const = 0; virtual bool equals_(const Value& other, double tol = 1e-9) const = 0;

View File

@ -64,7 +64,7 @@ void Argument::matlab_unwrap(FileWriter& file, const string& matlabName) const {
file.oss << cppType << " " << name << " = unwrap< "; file.oss << cppType << " " << name << " = unwrap< ";
file.oss << cppType << " >(" << matlabName; file.oss << cppType << " >(" << matlabName;
if (is_ptr || is_ref) file.oss << ", \"" << matlabType << "\""; if (is_ptr || is_ref) file.oss << ", \"ptr_" << matlabType << "\"";
file.oss << ");" << endl; file.oss << ");" << endl;
} }

View File

@ -1,168 +1,177 @@
/* ---------------------------------------------------------------------------- /* ----------------------------------------------------------------------------
* GTSAM Copyright 2010, Georgia Tech Research Corporation, * GTSAM Copyright 2010, Georgia Tech Research Corporation,
* Atlanta, Georgia 30332-0415 * Atlanta, Georgia 30332-0415
* All Rights Reserved * All Rights Reserved
* Authors: Frank Dellaert, et al. (see THANKS for the full author list) * Authors: Frank Dellaert, et al. (see THANKS for the full author list)
* See LICENSE for the license information * See LICENSE for the license information
* -------------------------------------------------------------------------- */ * -------------------------------------------------------------------------- */
/** /**
* @file Class.cpp * @file Class.cpp
* @author Frank Dellaert * @author Frank Dellaert
* @author Andrew Melim * @author Andrew Melim
**/ **/
#include <vector> #include <vector>
#include <iostream> #include <iostream>
#include <fstream> #include <fstream>
#include <stdint.h> #include <cstdint>
#include <boost/foreach.hpp> #include <boost/foreach.hpp>
#include <boost/lexical_cast.hpp> #include <boost/lexical_cast.hpp>
#include "Class.h" #include "Class.h"
#include "utilities.h" #include "utilities.h"
#include "Argument.h" #include "Argument.h"
using namespace std; using namespace std;
using namespace wrap; using namespace wrap;
/* ************************************************************************* */ /* ************************************************************************* */
void Class::matlab_proxy(const string& classFile, const string& wrapperName, FileWriter& wrapperFile, vector<string>& functionNames) const { void Class::matlab_proxy(const string& classFile, const string& wrapperName,
// open destination classFile const ReturnValue::TypeAttributesTable& typeAttributes,
FileWriter proxyFile(classFile, verbose_, "%"); FileWriter& wrapperFile, vector<string>& functionNames) const {
// open destination classFile
// get the name of actual matlab object FileWriter proxyFile(classFile, verbose_, "%");
const string matlabName = qualifiedName(), cppName = qualifiedName("::");
// get the name of actual matlab object
// emit class proxy code const string matlabName = qualifiedName(), cppName = qualifiedName("::");
// we want our class to inherit the handle class for memory purposes const string matlabBaseName = wrap::qualifiedName("", qualifiedParent);
proxyFile.oss << "classdef " << matlabName << " < handle" << endl; const string cppBaseName = wrap::qualifiedName("::", qualifiedParent);
proxyFile.oss << " properties" << endl;
proxyFile.oss << " self = 0" << endl; // emit class proxy code
proxyFile.oss << " end" << endl; // we want our class to inherit the handle class for memory purposes
proxyFile.oss << " methods" << endl; const string parent = qualifiedParent.empty() ?
"handle" : ::wrap::qualifiedName("", qualifiedParent);
// Constructor proxyFile.oss << "classdef " << matlabName << " < " << parent << endl;
proxyFile.oss << " function obj = " << matlabName << "(varargin)" << endl; proxyFile.oss << " properties" << endl;
// Special pointer constructors - one in MATLAB to create an object and proxyFile.oss << " ptr_" << matlabName << " = 0" << endl;
// assign a pointer returned from a C++ function. In turn this MATLAB proxyFile.oss << " end" << endl;
// constructor calls a special C++ function that just adds the object to proxyFile.oss << " methods" << endl;
// its collector. This allows wrapped functions to return objects in
// other wrap modules - to add these to their collectors the pointer is // Constructor
// passed from one C++ module into matlab then back into the other C++ proxyFile.oss << " function obj = " << matlabName << "(varargin)" << endl;
// module. // Special pointer constructors - one in MATLAB to create an object and
{ // assign a pointer returned from a C++ function. In turn this MATLAB
int id = functionNames.size(); // constructor calls a special C++ function that just adds the object to
const string functionName = pointer_constructor_fragments(proxyFile, wrapperFile, wrapperName, id); // its collector. This allows wrapped functions to return objects in
functionNames.push_back(functionName); // other wrap modules - to add these to their collectors the pointer is
} // passed from one C++ module into matlab then back into the other C++
// Regular constructors // module.
BOOST_FOREACH(ArgumentList a, constructor.args_list) {
{ int id = functionNames.size();
const int id = functionNames.size(); const string functionName = pointer_constructor_fragments(proxyFile, wrapperFile, wrapperName, id);
constructor.proxy_fragment(proxyFile, wrapperName, matlabName, id, a); functionNames.push_back(functionName);
const string wrapFunctionName = constructor.wrapper_fragment(wrapperFile, }
cppName, matlabName, id, using_namespaces, includes, a); // Regular constructors
wrapperFile.oss << "\n"; BOOST_FOREACH(ArgumentList a, constructor.args_list)
functionNames.push_back(wrapFunctionName); {
} const int id = functionNames.size();
proxyFile.oss << " else\n"; constructor.proxy_fragment(proxyFile, wrapperName, matlabName, matlabBaseName, id, a);
proxyFile.oss << " error('Arguments do not match any overload of " << matlabName << " constructor');" << endl; const string wrapFunctionName = constructor.wrapper_fragment(wrapperFile,
proxyFile.oss << " end\n"; cppName, matlabName, cppBaseName, id, using_namespaces, a);
proxyFile.oss << " end\n\n"; wrapperFile.oss << "\n";
functionNames.push_back(wrapFunctionName);
// Deconstructor }
{ proxyFile.oss << " else\n";
const int id = functionNames.size(); proxyFile.oss << " error('Arguments do not match any overload of " << matlabName << " constructor');" << endl;
deconstructor.proxy_fragment(proxyFile, wrapperName, matlabName, id); proxyFile.oss << " end\n";
proxyFile.oss << "\n"; if(!qualifiedParent.empty())
const string functionName = deconstructor.wrapper_fragment(wrapperFile, proxyFile.oss << " obj = obj@" << matlabBaseName << "(uint64(" << ptr_constructor_key << "), base_ptr);\n";
cppName, matlabName, id, using_namespaces, includes); proxyFile.oss << " obj.ptr_" << matlabName << " = my_ptr;\n";
wrapperFile.oss << "\n"; proxyFile.oss << " end\n\n";
functionNames.push_back(functionName);
} // Deconstructor
proxyFile.oss << " function display(obj), obj.print(''); end\n\n"; {
proxyFile.oss << " function disp(obj), obj.display; end\n\n"; const int id = functionNames.size();
deconstructor.proxy_fragment(proxyFile, wrapperName, matlabName, id);
// Methods proxyFile.oss << "\n";
BOOST_FOREACH(const Methods::value_type& name_m, methods) { const string functionName = deconstructor.wrapper_fragment(wrapperFile, cppName, matlabName, id, using_namespaces);
const Method& m = name_m.second; wrapperFile.oss << "\n";
m.proxy_wrapper_fragments(proxyFile, wrapperFile, cppName, matlabName, wrapperName, using_namespaces, functionNames); functionNames.push_back(functionName);
proxyFile.oss << "\n"; }
wrapperFile.oss << "\n"; proxyFile.oss << " function display(obj), obj.print(''); end\n\n";
} proxyFile.oss << " function disp(obj), obj.display; end\n\n";
proxyFile.oss << " end\n"; // Methods
proxyFile.oss << "\n"; BOOST_FOREACH(const Methods::value_type& name_m, methods) {
proxyFile.oss << " methods(Static = true)\n"; const Method& m = name_m.second;
m.proxy_wrapper_fragments(proxyFile, wrapperFile, cppName, matlabName, wrapperName, using_namespaces, typeAttributes, functionNames);
// Static methods proxyFile.oss << "\n";
BOOST_FOREACH(const StaticMethods::value_type& name_m, static_methods) { wrapperFile.oss << "\n";
const StaticMethod& m = name_m.second; }
m.proxy_wrapper_fragments(proxyFile, wrapperFile, cppName, matlabName, wrapperName, using_namespaces, functionNames);
proxyFile.oss << "\n"; proxyFile.oss << " end\n";
wrapperFile.oss << "\n"; proxyFile.oss << "\n";
} proxyFile.oss << " methods(Static = true)\n";
proxyFile.oss << " end" << endl; // Static methods
proxyFile.oss << "end" << endl; BOOST_FOREACH(const StaticMethods::value_type& name_m, static_methods) {
const StaticMethod& m = name_m.second;
// Close file m.proxy_wrapper_fragments(proxyFile, wrapperFile, cppName, matlabName, wrapperName, using_namespaces, typeAttributes, functionNames);
proxyFile.emit(true); proxyFile.oss << "\n";
} wrapperFile.oss << "\n";
}
/* ************************************************************************* */
string Class::qualifiedName(const string& delim) const { proxyFile.oss << " end" << endl;
string result; proxyFile.oss << "end" << endl;
BOOST_FOREACH(const string& ns, namespaces)
result += ns + delim; // Close file
return result + name; proxyFile.emit(true);
} }
/* ************************************************************************* */ /* ************************************************************************* */
string Class::pointer_constructor_fragments(FileWriter& proxyFile, FileWriter& wrapperFile, const string& wrapperName, int id) const { string Class::qualifiedName(const string& delim) const {
return ::wrap::qualifiedName(delim, namespaces, name);
static const uint64_t ptr_constructor_key = }
(uint64_t('G') << 56) |
(uint64_t('T') << 48) | /* ************************************************************************* */
(uint64_t('S') << 40) | string Class::pointer_constructor_fragments(FileWriter& proxyFile, FileWriter& wrapperFile, const string& wrapperName, int id) const {
(uint64_t('A') << 32) |
(uint64_t('M') << 24) | const string matlabName = qualifiedName(), cppName = qualifiedName("::");
(uint64_t('p') << 16) | const string wrapFunctionName = matlabName + "_collectorInsertAndMakeBase_" + boost::lexical_cast<string>(id);
(uint64_t('t') << 8) | const string baseMatlabName = wrap::qualifiedName("", qualifiedParent);
(uint64_t('r')); const string baseCppName = wrap::qualifiedName("::", qualifiedParent);
const string matlabName = qualifiedName(), cppName = qualifiedName("::"); // MATLAB constructor that assigns pointer to matlab object then calls c++
const string wrapFunctionName = matlabName + "_constructor_" + boost::lexical_cast<string>(id); // function to add the object to the collector.
proxyFile.oss << " if nargin == 2 && isa(varargin{1}, 'uint64') && ";
// MATLAB constructor that assigns pointer to matlab object then calls c++ proxyFile.oss << "varargin{1} == uint64(" << ptr_constructor_key << ")\n";
// function to add the object to the collector. proxyFile.oss << " my_ptr = varargin{2};\n";
proxyFile.oss << " if nargin == 2 && isa(varargin{1}, 'uint64') && "; if(qualifiedParent.empty()) // If this class has a base class, we'll get a base class pointer back
proxyFile.oss << "varargin{1} == uint64(" << ptr_constructor_key << ")\n"; proxyFile.oss << " ";
proxyFile.oss << " obj.self = varargin{2};\n"; else
proxyFile.oss << " " << wrapperName << "(obj.self);\n"; proxyFile.oss << " base_ptr = ";
proxyFile.oss << wrapperName << "(" << id << ", my_ptr);\n"; // Call collector insert and get base class ptr
// 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 // C++ function to add pointer from MATLAB to collector. The pointer always
// to a collector in a different wrap module. // comes from a C++ return value; this mechanism allows the object to be added
wrapperFile.oss << "void " << wrapFunctionName << "(int nargout, mxArray *out[], int nargin, const mxArray *in[])" << endl; // to a collector in a different wrap module. If this class has a base class,
wrapperFile.oss << "{\n"; // a new pointer to the base class is allocated and returned.
wrapperFile.oss << " mexAtExit(&_deleteAllObjects);\n"; wrapperFile.oss << "void " << wrapFunctionName << "(int nargout, mxArray *out[], int nargin, const mxArray *in[])" << endl;
generateUsingNamespace(wrapperFile, using_namespaces); wrapperFile.oss << "{\n";
// Typedef boost::shared_ptr wrapperFile.oss << " mexAtExit(&_deleteAllObjects);\n";
wrapperFile.oss << " typedef boost::shared_ptr<" << cppName << "> Shared;\n"; generateUsingNamespace(wrapperFile, using_namespaces);
wrapperFile.oss << "\n"; // Typedef boost::shared_ptr
// Get self pointer passed in wrapperFile.oss << " typedef boost::shared_ptr<" << cppName << "> Shared;\n";
wrapperFile.oss << " Shared *self = *reinterpret_cast<Shared**> (mxGetData(in[0]));\n"; wrapperFile.oss << "\n";
// Add to collector // Get self pointer passed in
wrapperFile.oss << " collector_" << matlabName << ".insert(self);\n"; wrapperFile.oss << " Shared *self = *reinterpret_cast<Shared**> (mxGetData(in[0]));\n";
wrapperFile.oss << "}\n"; // Add to collector
wrapperFile.oss << " collector_" << matlabName << ".insert(self);\n";
return wrapFunctionName; // If we have a base class, return the base class pointer (MATLAB will call the base class collectorInsertAndMakeBase to add this to the collector and recurse the heirarchy)
} if(!qualifiedParent.empty()) {
wrapperFile.oss << "\n";
/* ************************************************************************* */ wrapperFile.oss << " typedef boost::shared_ptr<" << baseCppName << "> SharedBase;\n";
wrapperFile.oss << " out[0] = mxCreateNumericMatrix(1, 1, mxUINT32OR64_CLASS, mxREAL);\n";
wrapperFile.oss << " *reinterpret_cast<SharedBase**>(mxGetData(out[0])) = new SharedBase(*self);\n";
}
wrapperFile.oss << "}\n";
return wrapFunctionName;
}
/* ************************************************************************* */

View File

@ -34,10 +34,12 @@ struct Class {
typedef std::map<std::string, StaticMethod> StaticMethods; typedef std::map<std::string, StaticMethod> StaticMethods;
/// Constructor creates an empty class /// Constructor creates an empty class
Class(bool verbose=true) : verbose_(verbose) {} Class(bool verbose=true) : verbose_(verbose), isVirtual(false) {}
// Then the instance variables are set directly by the Module constructor // Then the instance variables are set directly by the Module constructor
std::string name; ///< Class name std::string name; ///< Class name
bool isVirtual; ///< Whether the class is part of a virtual inheritance chain
std::vector<std::string> qualifiedParent; ///< The *single* parent - the last string is the parent class name, preceededing elements are a namespace stack
Methods methods; ///< Class methods Methods methods; ///< Class methods
StaticMethods static_methods; ///< Static methods StaticMethods static_methods; ///< Static methods
std::vector<std::string> namespaces; ///< Stack of namespaces std::vector<std::string> namespaces; ///< Stack of namespaces
@ -48,7 +50,7 @@ struct Class {
bool verbose_; ///< verbose flag bool verbose_; ///< verbose flag
// And finally MATLAB code is emitted, methods below called by Module::matlab_code // And finally MATLAB code is emitted, methods below called by Module::matlab_code
void matlab_proxy(const std::string& classFile, const std::string& wrapperName, void matlab_proxy(const std::string& classFile, const std::string& wrapperName, const ReturnValue::TypeAttributesTable& typeAttributes,
FileWriter& wrapperFile, std::vector<std::string>& functionNames) const; ///< emit proxy class FileWriter& wrapperFile, std::vector<std::string>& functionNames) const; ///< emit proxy class
std::string qualifiedName(const std::string& delim = "") const; ///< creates a namespace-qualified name, optional delimiter std::string qualifiedName(const std::string& delim = "") const; ///< creates a namespace-qualified name, optional delimiter

View File

@ -37,7 +37,7 @@ string Constructor::matlab_wrapper_name(const string& className) const {
/* ************************************************************************* */ /* ************************************************************************* */
void Constructor::proxy_fragment(FileWriter& file, const std::string& wrapperName, void Constructor::proxy_fragment(FileWriter& file, const std::string& wrapperName,
const string& className, const int id, const ArgumentList args) const { const string& matlabName, const string& matlabBaseName, const int id, const ArgumentList args) const {
size_t nrArgs = args.size(); size_t nrArgs = args.size();
// check for number of arguments... // check for number of arguments...
file.oss << " elseif nargin == " << nrArgs; file.oss << " elseif nargin == " << nrArgs;
@ -50,10 +50,14 @@ void Constructor::proxy_fragment(FileWriter& file, const std::string& wrapperNam
first=false; first=false;
} }
// emit code for calling constructor // emit code for calling constructor
file.oss << "\n obj.self = " << wrapperName << "(" << id; if(matlabBaseName.empty())
file.oss << "\n my_ptr = ";
else
file.oss << "\n [ my_ptr, base_ptr ] = ";
file.oss << wrapperName << "(" << id;
// emit constructor arguments // emit constructor arguments
for(size_t i=0;i<nrArgs;i++) { for(size_t i=0;i<nrArgs;i++) {
file.oss << ","; file.oss << ", ";
file.oss << "varargin{" << i+1 << "}"; file.oss << "varargin{" << i+1 << "}";
} }
file.oss << ");\n"; file.oss << ");\n";
@ -63,9 +67,9 @@ void Constructor::proxy_fragment(FileWriter& file, const std::string& wrapperNam
string Constructor::wrapper_fragment(FileWriter& file, string Constructor::wrapper_fragment(FileWriter& file,
const string& cppClassName, const string& cppClassName,
const string& matlabClassName, const string& matlabClassName,
const string& cppBaseClassName,
int id, int id,
const vector<string>& using_namespaces, const vector<string>& using_namespaces,
const vector<string>& includes,
const ArgumentList& al) const { const ArgumentList& al) const {
const string wrapFunctionName = matlabClassName + "_constructor_" + boost::lexical_cast<string>(id); const string wrapFunctionName = matlabClassName + "_constructor_" + boost::lexical_cast<string>(id);
@ -89,6 +93,14 @@ string Constructor::wrapper_fragment(FileWriter& file,
file.oss << " out[0] = mxCreateNumericMatrix(1, 1, mxUINT32OR64_CLASS, mxREAL);" << endl; file.oss << " out[0] = mxCreateNumericMatrix(1, 1, mxUINT32OR64_CLASS, mxREAL);" << endl;
file.oss << " *reinterpret_cast<Shared**> (mxGetData(out[0])) = self;" << endl; file.oss << " *reinterpret_cast<Shared**> (mxGetData(out[0])) = self;" << endl;
// If we have a base class, return the base class pointer (MATLAB will call the base class collectorInsertAndMakeBase to add this to the collector and recurse the heirarchy)
if(!cppBaseClassName.empty()) {
file.oss << "\n";
file.oss << " typedef boost::shared_ptr<" << cppBaseClassName << "> SharedBase;\n";
file.oss << " out[1] = mxCreateNumericMatrix(1, 1, mxUINT32OR64_CLASS, mxREAL);\n";
file.oss << " *reinterpret_cast<SharedBase**>(mxGetData(out[1])) = new SharedBase(*self);\n";
}
file.oss << "}" << endl; file.oss << "}" << endl;
return wrapFunctionName; return wrapFunctionName;

View File

@ -49,16 +49,16 @@ struct Constructor {
* if nargin == 2, obj.self = new_Pose3_RP(varargin{1},varargin{2}); end * if nargin == 2, obj.self = new_Pose3_RP(varargin{1},varargin{2}); end
*/ */
void proxy_fragment(FileWriter& file, const std::string& wrapperName, void proxy_fragment(FileWriter& file, const std::string& wrapperName,
const std::string& className, const int id, const std::string& className, const std::string& matlabBaseName, const int id,
const ArgumentList args) const; const ArgumentList args) const;
/// cpp wrapper /// cpp wrapper
std::string wrapper_fragment(FileWriter& file, std::string wrapper_fragment(FileWriter& file,
const std::string& cppClassName, const std::string& cppClassName,
const std::string& matlabClassName, const std::string& matlabClassName,
const std::string& cppBaseClassName,
int id, int id,
const std::vector<std::string>& using_namespaces, const std::vector<std::string>& using_namespaces,
const std::vector<std::string>& includes,
const ArgumentList& al) const; const ArgumentList& al) const;
/// constructor function /// constructor function

View File

@ -39,7 +39,7 @@ void Deconstructor::proxy_fragment(FileWriter& file,
const std::string& qualifiedMatlabName, int id) const { const std::string& qualifiedMatlabName, int id) const {
file.oss << " function delete(obj)\n"; file.oss << " function delete(obj)\n";
file.oss << " " << wrapperName << "(" << id << ", obj.self);\n"; file.oss << " " << wrapperName << "(" << id << ", obj.ptr_" << qualifiedMatlabName << ");\n";
file.oss << " end\n"; file.oss << " end\n";
} }
@ -48,7 +48,7 @@ string Deconstructor::wrapper_fragment(FileWriter& file,
const string& cppClassName, const string& cppClassName,
const string& matlabClassName, const string& matlabClassName,
int id, int id,
const vector<string>& using_namespaces, const vector<string>& includes) const { const vector<string>& using_namespaces) const {
const string matlabName = matlab_wrapper_name(matlabClassName); const string matlabName = matlab_wrapper_name(matlabClassName);

View File

@ -55,8 +55,7 @@ struct Deconstructor {
const std::string& cppClassName, const std::string& cppClassName,
const std::string& matlabClassName, const std::string& matlabClassName,
int id, int id,
const std::vector<std::string>& using_namespaces, const std::vector<std::string>& using_namespaces) const;
const std::vector<std::string>& includes) const;
}; };
} // \namespace wrap } // \namespace wrap

View File

@ -41,9 +41,10 @@ void Method::proxy_wrapper_fragments(FileWriter& proxyFile, FileWriter& wrapperF
const string& matlabClassName, const string& matlabClassName,
const string& wrapperName, const string& wrapperName,
const vector<string>& using_namespaces, const vector<string>& using_namespaces,
const ReturnValue::TypeAttributesTable& typeAttributes,
vector<string>& functionNames) const { vector<string>& 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) { for(size_t overload = 0; overload < argLists.size(); ++overload) {
const ArgumentList& args = argLists[overload]; const ArgumentList& args = argLists[overload];
@ -74,12 +75,12 @@ void Method::proxy_wrapper_fragments(FileWriter& proxyFile, FileWriter& wrapperF
output = ""; output = "";
else else
output = "varargout{1} = "; output = "varargout{1} = ";
proxyFile.oss << " " << output << wrapperName << "(" << id << ", self, varargin{:});\n"; proxyFile.oss << " " << output << wrapperName << "(" << id << ", this, varargin{:});\n";
// Output C++ wrapper code // Output C++ wrapper code
const string wrapFunctionName = wrapper_fragment( const string wrapFunctionName = wrapper_fragment(
wrapperFile, cppClassName, matlabClassName, overload, id, using_namespaces); wrapperFile, cppClassName, matlabClassName, overload, id, using_namespaces, typeAttributes);
// Add to function list // Add to function list
functionNames.push_back(wrapFunctionName); functionNames.push_back(wrapFunctionName);
@ -100,7 +101,8 @@ string Method::wrapper_fragment(FileWriter& file,
const string& matlabClassName, const string& matlabClassName,
int overload, int overload,
int id, int id,
const vector<string>& using_namespaces) const { const vector<string>& using_namespaces,
const ReturnValue::TypeAttributesTable& typeAttributes) const {
// generate code // generate code
@ -135,20 +137,16 @@ string Method::wrapper_fragment(FileWriter& file,
// get class pointer // get class pointer
// example: shared_ptr<Test> = unwrap_shared_ptr< Test >(in[0], "Test"); // example: shared_ptr<Test> = 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 // unwrap arguments, see Argument.cpp
args.matlab_unwrap(file,1); args.matlab_unwrap(file,1);
// call method // call method and wrap result
// example: bool result = self->return_field(t); // example: out[0]=wrap<bool>(self->return_field(t));
file.oss << " ";
if (returnVal.type1!="void") if (returnVal.type1!="void")
file.oss << returnVal.return_type(true,ReturnValue::pair) << " result = "; returnVal.wrap_result("obj->"+name+"("+args.names()+")", file, typeAttributes);
file.oss << "obj->" << name << "(" << args.names() << ");\n"; else
file.oss << " obj->"+name+"("+args.names()+");\n";
// wrap result
// example: out[0]=wrap<bool>(result);
returnVal.wrap_result(file);
// finish // finish
file.oss << "}\n"; file.oss << "}\n";

View File

@ -50,6 +50,7 @@ struct Method {
void proxy_wrapper_fragments(FileWriter& proxyFile, FileWriter& wrapperFile, void proxy_wrapper_fragments(FileWriter& proxyFile, FileWriter& wrapperFile,
const std::string& cppClassName, const std::string& matlabClassName, const std::string& cppClassName, const std::string& matlabClassName,
const std::string& wrapperName, const std::vector<std::string>& using_namespaces, const std::string& wrapperName, const std::vector<std::string>& using_namespaces,
const ReturnValue::TypeAttributesTable& typeAttributes,
std::vector<std::string>& functionNames) const; std::vector<std::string>& functionNames) const;
private: private:
@ -58,7 +59,8 @@ private:
const std::string& matlabClassname, const std::string& matlabClassname,
int overload, int overload,
int id, int id,
const std::vector<std::string>& using_namespaces) const; ///< cpp wrapper const std::vector<std::string>& using_namespaces,
const ReturnValue::TypeAttributesTable& typeAttributes) const; ///< cpp wrapper
}; };
} // \namespace wrap } // \namespace wrap

View File

@ -24,8 +24,10 @@
//#define BOOST_SPIRIT_DEBUG //#define BOOST_SPIRIT_DEBUG
#include <boost/spirit/include/classic_confix.hpp> #include <boost/spirit/include/classic_confix.hpp>
#include <boost/spirit/include/classic_clear_actor.hpp> #include <boost/spirit/include/classic_clear_actor.hpp>
#include <boost/spirit/include/classic_insert_at_actor.hpp>
#include <boost/lambda/bind.hpp> #include <boost/lambda/bind.hpp>
#include <boost/lambda/lambda.hpp> #include <boost/lambda/lambda.hpp>
#include <boost/lambda/construct.hpp>
#include <boost/foreach.hpp> #include <boost/foreach.hpp>
#include <boost/filesystem.hpp> #include <boost/filesystem.hpp>
#include <boost/lexical_cast.hpp> #include <boost/lexical_cast.hpp>
@ -65,12 +67,12 @@ Module::Module(const string& interfacePath,
//Method method0(enable_verbose), method(enable_verbose); //Method method0(enable_verbose), method(enable_verbose);
StaticMethod static_method0(enable_verbose), static_method(enable_verbose); StaticMethod static_method0(enable_verbose), static_method(enable_verbose);
Class cls0(enable_verbose),cls(enable_verbose); Class cls0(enable_verbose),cls(enable_verbose);
ForwardDeclaration fwDec0, fwDec;
vector<string> namespaces, /// current namespace tag vector<string> namespaces, /// current namespace tag
namespace_includes, /// current set of includes namespace_includes, /// current set of includes
namespaces_return, /// namespace for current return type namespaces_return, /// namespace for current return type
using_namespace_current; /// All namespaces from "using" declarations using_namespace_current; /// All namespaces from "using" declarations
string include_path = ""; string include_path = "";
string class_name = "";
const string null_str = ""; const string null_str = "";
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
@ -93,7 +95,7 @@ Module::Module(const string& interfacePath,
Rule eigenType_p = Rule eigenType_p =
(str_p("Vector") | "Matrix"); (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; Rule namespace_name_p = lexeme_d[lower_p >> *(alnum_p | '_')] - keywords_p;
@ -114,6 +116,10 @@ Module::Module(const string& interfacePath,
className_p[assign_a(arg.type)] >> className_p[assign_a(arg.type)] >>
(ch_p('*')[assign_a(arg.is_ptr,true)] | ch_p('&')[assign_a(arg.is_ref,true)]); (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 name_p = lexeme_d[alpha_p >> *(alnum_p | '_')];
Rule argument_p = Rule argument_p =
@ -196,9 +202,10 @@ Module::Module(const string& interfacePath,
Rule class_p = Rule class_p =
(!*include_p (!*include_p
>> !(str_p("virtual")[assign_a(cls.isVirtual, true)])
>> str_p("class")[push_back_a(cls.includes, include_path)][assign_a(include_path, null_str)] >> str_p("class")[push_back_a(cls.includes, include_path)][assign_a(include_path, null_str)]
>> className_p[assign_a(cls.name)] >> 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) >> *(functions_p | comments_p)
>> str_p("};")) >> str_p("};"))
[assign_a(constructor.name, cls.name)] [assign_a(constructor.name, cls.name)]
@ -208,7 +215,7 @@ Module::Module(const string& interfacePath,
[append_a(cls.includes, namespace_includes)] [append_a(cls.includes, namespace_includes)]
[assign_a(deconstructor.name,cls.name)] [assign_a(deconstructor.name,cls.name)]
[assign_a(cls.deconstructor, deconstructor)] [assign_a(cls.deconstructor, deconstructor)]
[push_back_a(classes,cls)] [push_back_a(classes, cls)]
[assign_a(deconstructor,deconstructor0)] [assign_a(deconstructor,deconstructor0)]
[assign_a(constructor, constructor0)] [assign_a(constructor, constructor0)]
[assign_a(cls,cls0)]; [assign_a(cls,cls0)];
@ -229,9 +236,12 @@ Module::Module(const string& interfacePath,
>> namespace_name_p[push_back_a(using_namespace_current)] >> ch_p(';'); >> namespace_name_p[push_back_a(using_namespace_current)] >> ch_p(';');
Rule forward_declaration_p = Rule forward_declaration_p =
str_p("class") >> !(str_p("virtual")[assign_a(fwDec.isVirtual, true)])
(*(namespace_name_p >> str_p("::")) >> className_p)[push_back_a(forward_declarations)] >> str_p("class")
>> ch_p(';'); >> (*(namespace_name_p >> str_p("::")) >> className_p)[assign_a(fwDec.name)]
>> ch_p(';')
[push_back_a(forward_declarations, fwDec)]
[assign_a(fwDec, fwDec0)];
Rule module_content_p = comments_p | using_namespace_p | class_p | forward_declaration_p | namespace_def_p ; Rule module_content_p = comments_p | using_namespace_p | class_p | forward_declaration_p | namespace_def_p ;
@ -321,7 +331,10 @@ void Module::matlab_code(const string& toolboxPath, const string& headerPath) co
wrapperFile.oss << "\n"; wrapperFile.oss << "\n";
// Dependency check list // Dependency check list
vector<string> validTypes = forward_declarations; vector<string> validTypes;
BOOST_FOREACH(const ForwardDeclaration& fwDec, forward_declarations) {
validTypes.push_back(fwDec.name);
}
validTypes.push_back("void"); validTypes.push_back("void");
validTypes.push_back("string"); validTypes.push_back("string");
validTypes.push_back("int"); validTypes.push_back("int");
@ -333,18 +346,31 @@ void Module::matlab_code(const string& toolboxPath, const string& headerPath) co
validTypes.push_back("Vector"); validTypes.push_back("Vector");
validTypes.push_back("Matrix"); validTypes.push_back("Matrix");
//Create a list of parsed classes for dependency checking //Create a list of parsed classes for dependency checking
BOOST_FOREACH(Class cls, classes) { BOOST_FOREACH(const Class& cls, classes) {
validTypes.push_back(cls.qualifiedName("::")); validTypes.push_back(cls.qualifiedName("::"));
} }
// Create type attributes table
ReturnValue::TypeAttributesTable typeAttributes;
BOOST_FOREACH(const ForwardDeclaration& fwDec, forward_declarations) {
if(!typeAttributes.insert(make_pair(fwDec.name, ReturnValue::TypeAttributes(fwDec.isVirtual))).second)
throw DuplicateDefinition("class " + fwDec.name);
}
BOOST_FOREACH(const Class& cls, classes) {
if(!typeAttributes.insert(make_pair(cls.qualifiedName("::"), ReturnValue::TypeAttributes(cls.isVirtual))).second)
throw DuplicateDefinition("class " + cls.qualifiedName("::"));
// Check that class is virtual if it has a parent
}
// Generate all includes // Generate all includes
BOOST_FOREACH(Class cls, classes) { BOOST_FOREACH(const Class& cls, classes) {
generateIncludes(wrapperFile, cls.name, cls.includes); generateIncludes(wrapperFile, cls.name, cls.includes);
} }
wrapperFile.oss << "\n"; wrapperFile.oss << "\n";
// Generate all collectors // Generate all collectors
BOOST_FOREACH(Class cls, classes) { BOOST_FOREACH(const Class& cls, classes) {
const string matlabName = cls.qualifiedName(), cppName = cls.qualifiedName("::"); const string matlabName = cls.qualifiedName(), cppName = cls.qualifiedName("::");
wrapperFile.oss << "typedef std::set<boost::shared_ptr<" << cppName << ">*> " wrapperFile.oss << "typedef std::set<boost::shared_ptr<" << cppName << ">*> "
<< "Collector_" << matlabName << ";\n"; << "Collector_" << matlabName << ";\n";
@ -355,7 +381,7 @@ void Module::matlab_code(const string& toolboxPath, const string& headerPath) co
// generate mexAtExit cleanup function // generate mexAtExit cleanup function
wrapperFile.oss << "void _deleteAllObjects()\n"; wrapperFile.oss << "void _deleteAllObjects()\n";
wrapperFile.oss << "{\n"; wrapperFile.oss << "{\n";
BOOST_FOREACH(Class cls, classes) { BOOST_FOREACH(const Class& cls, classes) {
const string matlabName = cls.qualifiedName(); const string matlabName = cls.qualifiedName();
const string cppName = cls.qualifiedName("::"); const string cppName = cls.qualifiedName("::");
const string collectorType = "Collector_" + matlabName; const string collectorType = "Collector_" + matlabName;
@ -369,10 +395,10 @@ void Module::matlab_code(const string& toolboxPath, const string& headerPath) co
wrapperFile.oss << "}\n"; wrapperFile.oss << "}\n";
// generate proxy classes and wrappers // generate proxy classes and wrappers
BOOST_FOREACH(Class cls, classes) { BOOST_FOREACH(const Class& cls, classes) {
// create proxy class and wrapper code // create proxy class and wrapper code
string classFile = toolboxPath + "/" + cls.qualifiedName() + ".m"; string classFile = toolboxPath + "/" + cls.qualifiedName() + ".m";
cls.matlab_proxy(classFile, wrapperName, wrapperFile, functionNames); cls.matlab_proxy(classFile, wrapperName, typeAttributes, wrapperFile, functionNames);
// verify all of the function arguments // verify all of the function arguments
//TODO:verifyArguments<ArgumentList>(validTypes, cls.constructor.args_list); //TODO:verifyArguments<ArgumentList>(validTypes, cls.constructor.args_list);

View File

@ -19,6 +19,7 @@
#include <string> #include <string>
#include <vector> #include <vector>
#include <map>
#include "Class.h" #include "Class.h"
@ -28,11 +29,18 @@ namespace wrap {
* A module just has a name and a list of classes * A module just has a name and a list of classes
*/ */
struct Module { struct Module {
struct ForwardDeclaration {
std::string name;
bool isVirtual;
ForwardDeclaration() : isVirtual(false) {}
};
std::string name; ///< module name std::string name; ///< module name
std::vector<Class> classes; ///< list of classes std::vector<Class> classes; ///< list of classes
bool verbose; ///< verbose flag bool verbose; ///< verbose flag
// std::vector<std::string> using_namespaces; ///< all default namespaces // std::vector<std::string> using_namespaces; ///< all default namespaces
std::vector<std::string> forward_declarations; std::vector<ForwardDeclaration> forward_declarations;
/// constructor that parses interface file /// constructor that parses interface file
Module(const std::string& interfacePath, Module(const std::string& interfacePath,

View File

@ -46,45 +46,60 @@ string ReturnValue::qualifiedType2(const string& delim) const {
/* ************************************************************************* */ /* ************************************************************************* */
//TODO:Fix this //TODO:Fix this
void ReturnValue::wrap_result(FileWriter& file) const { void ReturnValue::wrap_result(const string& result, FileWriter& file, const TypeAttributesTable& typeAttributes) const {
string cppType1 = qualifiedType1("::"), matlabType1 = qualifiedType1(); string cppType1 = qualifiedType1("::"), matlabType1 = qualifiedType1();
string cppType2 = qualifiedType2("::"), matlabType2 = qualifiedType2(); string cppType2 = qualifiedType2("::"), matlabType2 = qualifiedType2();
if (isPair) { if (isPair) {
// first return value in pair // first return value in pair
if (isPtr1) {// if we already have a pointer if (isPtr1) {// if we already have a pointer
file.oss << " Shared" << type1 <<"* ret = new Shared" << type1 << "(result.first);" << endl; file.oss << " Shared" << type1 <<"* ret = new Shared" << type1 << "(" << result << ".first);" << endl;
file.oss << " out[0] = wrap_shared_ptr(ret,\"" << matlabType1 << "\");\n"; file.oss << " out[0] = wrap_shared_ptr(ret,\"" << matlabType1 << "\");\n";
} }
else if (category1 == ReturnValue::CLASS) { // if we are going to make one else if (category1 == ReturnValue::CLASS) { // if we are going to make one
file.oss << " Shared" << type1 << "* ret = new Shared" << type1 << "(new " << cppType1 << "(result.first));\n"; string objCopy;
if(typeAttributes.at(cppType1).isVirtual)
objCopy = "boost::dynamic_pointer_cast<" + cppType1 + ">(" + result + ".first.clone())";
else
objCopy = "new " + cppType1 + "(" + result + ".first)";
file.oss << " Shared" << type1 << "* ret = new Shared" << type1 << "(" << objCopy << ");\n";
file.oss << " out[0] = wrap_shared_ptr(ret,\"" << matlabType1 << "\");\n"; file.oss << " out[0] = wrap_shared_ptr(ret,\"" << matlabType1 << "\");\n";
} }
else // if basis type else // if basis type
file.oss << " out[0] = wrap< " << return_type(true,arg1) << " >(result.first);\n"; file.oss << " out[0] = wrap< " << return_type(true,arg1) << " >(" << result << ".first);\n";
// second return value in pair // second return value in pair
if (isPtr2) {// if we already have a pointer if (isPtr2) {// if we already have a pointer
file.oss << " Shared" << type2 <<"* ret = new Shared" << type2 << "(result.second);" << endl; file.oss << " Shared" << type2 <<"* ret = new Shared" << type2 << "(" << result << ".second);" << endl;
file.oss << " out[1] = wrap_shared_ptr(ret,\"" << matlabType2 << "\");\n"; file.oss << " out[1] = wrap_shared_ptr(ret,\"" << matlabType2 << "\");\n";
} }
else if (category2 == ReturnValue::CLASS) { // if we are going to make one else if (category2 == ReturnValue::CLASS) { // if we are going to make one
file.oss << " Shared" << type2 << "* ret = new Shared" << type2 << "(new " << cppType2 << "(result.first));\n"; string objCopy;
if(typeAttributes.at(cppType1).isVirtual)
objCopy = "boost::dynamic_pointer_cast<" + cppType2 + ">(" + result + ".second.clone())";
else
objCopy = "new " + cppType1 + "(" + result + ".second)";
file.oss << " Shared" << type2 << "* ret = new Shared" << type2 << "(" << objCopy << ");\n";
file.oss << " out[0] = wrap_shared_ptr(ret,\"" << matlabType2 << "\");\n"; file.oss << " out[0] = wrap_shared_ptr(ret,\"" << matlabType2 << "\");\n";
} }
else else
file.oss << " out[1] = wrap< " << return_type(true,arg2) << " >(result.second);\n"; file.oss << " out[1] = wrap< " << return_type(true,arg2) << " >(" << result << ".second);\n";
} }
else if (isPtr1){ else if (isPtr1){
file.oss << " Shared" << type1 <<"* ret = new Shared" << type1 << "(result);" << endl; file.oss << " Shared" << type1 <<"* ret = new Shared" << type1 << "(" << result << ");" << endl;
file.oss << " out[0] = wrap_shared_ptr(ret,\"" << matlabType1 << "\");\n"; file.oss << " out[0] = wrap_shared_ptr(ret,\"" << matlabType1 << "\");\n";
} }
else if (category1 == ReturnValue::CLASS){ else if (category1 == ReturnValue::CLASS){
file.oss << " Shared" << type1 << "* ret = new Shared" << type1 << "(new " << cppType1 << "(result));\n"; string objCopy;
if(typeAttributes.at(cppType1).isVirtual)
objCopy = "boost::dynamic_pointer_cast<" + cppType1 + ">(" + result + ".clone())";
else
objCopy = "new " + cppType1 + "(" + result + ")";
file.oss << " Shared" << type1 << "* ret = new Shared" << type1 << "(" << objCopy << ");\n";
file.oss << " out[0] = wrap_shared_ptr(ret,\"" << matlabType1 << "\");\n"; file.oss << " out[0] = wrap_shared_ptr(ret,\"" << matlabType1 << "\");\n";
} }
else if (matlabType1!="void") else if (matlabType1!="void")
file.oss << " out[0] = wrap< " << return_type(true,arg1) << " >(result);\n"; file.oss << " out[0] = wrap< " << return_type(true,arg1) << " >(" << result << ");\n";
} }
/* ************************************************************************* */ /* ************************************************************************* */

View File

@ -8,6 +8,7 @@
*/ */
#include <vector> #include <vector>
#include <map>
#include "FileWriter.h" #include "FileWriter.h"
@ -17,6 +18,14 @@ namespace wrap {
struct ReturnValue { struct ReturnValue {
struct TypeAttributes {
bool isVirtual;
TypeAttributes() : isVirtual(false) {}
TypeAttributes(bool isVirtual) : isVirtual(isVirtual) {}
};
typedef std::map<std::string, TypeAttributes> TypeAttributesTable;
typedef enum { typedef enum {
CLASS, CLASS,
EIGEN, EIGEN,
@ -47,7 +56,7 @@ struct ReturnValue {
std::string matlab_returnType() const; std::string matlab_returnType() const;
void wrap_result(FileWriter& file) const; void wrap_result(const std::string& result, FileWriter& file, const TypeAttributesTable& typeAttributes) const;
}; };

View File

@ -42,6 +42,7 @@ void StaticMethod::proxy_wrapper_fragments(FileWriter& proxyFile, FileWriter& wr
const string& matlabClassName, const string& matlabClassName,
const string& wrapperName, const string& wrapperName,
const vector<string>& using_namespaces, const vector<string>& using_namespaces,
const ReturnValue::TypeAttributesTable& typeAttributes,
vector<string>& functionNames) const { vector<string>& functionNames) const {
string upperName = name; upperName[0] = std::toupper(upperName[0], std::locale()); string upperName = name; upperName[0] = std::toupper(upperName[0], std::locale());
@ -82,7 +83,7 @@ void StaticMethod::proxy_wrapper_fragments(FileWriter& proxyFile, FileWriter& wr
// Output C++ wrapper code // Output C++ wrapper code
const string wrapFunctionName = wrapper_fragment( const string wrapFunctionName = wrapper_fragment(
wrapperFile, cppClassName, matlabClassName, overload, id, using_namespaces); wrapperFile, cppClassName, matlabClassName, overload, id, using_namespaces, typeAttributes);
// Add to function list // Add to function list
functionNames.push_back(wrapFunctionName); functionNames.push_back(wrapFunctionName);
@ -103,7 +104,8 @@ string StaticMethod::wrapper_fragment(FileWriter& file,
const string& matlabClassName, const string& matlabClassName,
int overload, int overload,
int id, int id,
const vector<string>& using_namespaces) const { const vector<string>& using_namespaces,
const ReturnValue::TypeAttributesTable& typeAttributes) const {
// generate code // generate code
@ -140,14 +142,11 @@ string StaticMethod::wrapper_fragment(FileWriter& file,
file.oss << " "; file.oss << " ";
// call method with default type // call method with default type and wrap result
if (returnVal.type1!="void") if (returnVal.type1!="void")
file.oss << returnVal.return_type(true,ReturnValue::pair) << " result = "; returnVal.wrap_result(cppClassName+"::"+name+"("+args.names()+")", file, typeAttributes);
file.oss << cppClassName << "::" << name << "(" << args.names() << ");\n"; else
file.oss << cppClassName+"::"+name+"("+args.names()+");\n";
// wrap result
// example: out[0]=wrap<bool>(result);
returnVal.wrap_result(file);
// finish // finish
file.oss << "}\n"; file.oss << "}\n";

View File

@ -50,6 +50,7 @@ struct StaticMethod {
void proxy_wrapper_fragments(FileWriter& proxyFile, FileWriter& wrapperFile, void proxy_wrapper_fragments(FileWriter& proxyFile, FileWriter& wrapperFile,
const std::string& cppClassName, const std::string& matlabClassName, const std::string& cppClassName, const std::string& matlabClassName,
const std::string& wrapperName, const std::vector<std::string>& using_namespaces, const std::string& wrapperName, const std::vector<std::string>& using_namespaces,
const ReturnValue::TypeAttributesTable& typeAttributes,
std::vector<std::string>& functionNames) const; std::vector<std::string>& functionNames) const;
private: private:
@ -58,7 +59,8 @@ private:
const std::string& matlabClassname, const std::string& matlabClassname,
int overload, int overload,
int id, int id,
const std::vector<std::string>& using_namespaces) const; ///< cpp wrapper const std::vector<std::string>& using_namespaces,
const ReturnValue::TypeAttributesTable& typeAttributes) const; ///< cpp wrapper
}; };
} // \namespace wrap } // \namespace wrap

View File

@ -56,7 +56,7 @@ using namespace boost; // not usual, but for conciseness of generated code
#endif #endif
// "Unique" key to signal calling the matlab object constructor with a raw pointer // "Unique" key to signal calling the matlab object constructor with a raw pointer
// Also present in Class.cpp // Also present in utilities.h
static const uint64_t ptr_constructor_key = static const uint64_t ptr_constructor_key =
(uint64_t('G') << 56) | (uint64_t('G') << 56) |
(uint64_t('T') << 48) | (uint64_t('T') << 48) |
@ -119,7 +119,7 @@ void checkArguments(const string& name, int nargout, int nargin, int expected) {
// default wrapping throws an error: only basis types are allowed in wrap // default wrapping throws an error: only basis types are allowed in wrap
template <typename Class> template <typename Class>
mxArray* wrap(Class& value) { mxArray* wrap(const Class& value) {
error("wrap internal error: attempted wrap of invalid type"); error("wrap internal error: attempted wrap of invalid type");
return 0; return 0;
} }
@ -127,13 +127,13 @@ mxArray* wrap(Class& value) {
// specialization to string // specialization to string
// wraps into a character array // wraps into a character array
template<> template<>
mxArray* wrap<string>(string& value) { mxArray* wrap<string>(const string& value) {
return mxCreateString(value.c_str()); return mxCreateString(value.c_str());
} }
// specialization to char // specialization to char
template<> template<>
mxArray* wrap<char>(char& value) { mxArray* wrap<char>(const char& value) {
mxArray *result = scalar(mxUINT32OR64_CLASS); mxArray *result = scalar(mxUINT32OR64_CLASS);
*(char*)mxGetData(result) = value; *(char*)mxGetData(result) = value;
return result; return result;
@ -141,7 +141,7 @@ mxArray* wrap<char>(char& value) {
// specialization to unsigned char // specialization to unsigned char
template<> template<>
mxArray* wrap<unsigned char>(unsigned char& value) { mxArray* wrap<unsigned char>(const unsigned char& value) {
mxArray *result = scalar(mxUINT32OR64_CLASS); mxArray *result = scalar(mxUINT32OR64_CLASS);
*(unsigned char*)mxGetData(result) = value; *(unsigned char*)mxGetData(result) = value;
return result; return result;
@ -149,7 +149,7 @@ mxArray* wrap<unsigned char>(unsigned char& value) {
// specialization to bool // specialization to bool
template<> template<>
mxArray* wrap<bool>(bool& value) { mxArray* wrap<bool>(const bool& value) {
mxArray *result = scalar(mxUINT32OR64_CLASS); mxArray *result = scalar(mxUINT32OR64_CLASS);
*(bool*)mxGetData(result) = value; *(bool*)mxGetData(result) = value;
return result; return result;
@ -157,7 +157,7 @@ mxArray* wrap<bool>(bool& value) {
// specialization to size_t // specialization to size_t
template<> template<>
mxArray* wrap<size_t>(size_t& value) { mxArray* wrap<size_t>(const size_t& value) {
mxArray *result = scalar(mxUINT32OR64_CLASS); mxArray *result = scalar(mxUINT32OR64_CLASS);
*(size_t*)mxGetData(result) = value; *(size_t*)mxGetData(result) = value;
return result; return result;
@ -165,7 +165,7 @@ mxArray* wrap<size_t>(size_t& value) {
// specialization to int // specialization to int
template<> template<>
mxArray* wrap<int>(int& value) { mxArray* wrap<int>(const int& value) {
mxArray *result = scalar(mxUINT32OR64_CLASS); mxArray *result = scalar(mxUINT32OR64_CLASS);
*(int*)mxGetData(result) = value; *(int*)mxGetData(result) = value;
return result; return result;
@ -173,7 +173,7 @@ mxArray* wrap<int>(int& value) {
// specialization to double -> just double // specialization to double -> just double
template<> template<>
mxArray* wrap<double>(double& value) { mxArray* wrap<double>(const double& value) {
return mxCreateDoubleScalar(value); return mxCreateDoubleScalar(value);
} }
@ -188,13 +188,7 @@ mxArray* wrap_Vector(const gtsam::Vector& v) {
// specialization to Eigen vector -> double vector // specialization to Eigen vector -> double vector
template<> template<>
mxArray* wrap<gtsam::Vector >(gtsam::Vector& v) { mxArray* wrap<gtsam::Vector >(const gtsam::Vector& v) {
return wrap_Vector(v);
}
// const version
template<>
mxArray* wrap<const gtsam::Vector >(const gtsam::Vector& v) {
return wrap_Vector(v); return wrap_Vector(v);
} }
@ -214,13 +208,7 @@ mxArray* wrap_Matrix(const gtsam::Matrix& A) {
// specialization to Eigen MATRIX -> double matrix // specialization to Eigen MATRIX -> double matrix
template<> template<>
mxArray* wrap<gtsam::Matrix >(gtsam::Matrix& A) { mxArray* wrap<gtsam::Matrix >(const gtsam::Matrix& A) {
return wrap_Matrix(A);
}
// const version
template<>
mxArray* wrap<const gtsam::Matrix >(const gtsam::Matrix& A) {
return wrap_Matrix(A); return wrap_Matrix(A);
} }
@ -342,9 +330,14 @@ gtsam::Matrix unwrap< gtsam::Matrix >(const mxArray* array) {
[create_object] creates a MATLAB proxy class object with a mexhandle [create_object] creates a MATLAB proxy class object with a mexhandle
in the self property. Matlab does not allow the creation of matlab 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 objects from within mex files, hence we resort to an ugly trick: we
invoke the proxy class constructor by calling MATLAB, and pass 13 invoke the proxy class constructor by calling MATLAB with a special
dummy arguments to let the constructor know we want an object without uint64 value ptr_constructor_key and the pointer itself. MATLAB
the self property initialized. We then assign the mexhandle to self. 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* create_object(const char *classname, void *pointer) {
mxArray *result; mxArray *result;
@ -376,9 +369,9 @@ mxArray* wrap_shared_ptr(boost::shared_ptr< Class >* shared_ptr, const char *cla
} }
template <typename Class> template <typename Class>
boost::shared_ptr<Class> unwrap_shared_ptr(const mxArray* obj, const string& className) { boost::shared_ptr<Class> unwrap_shared_ptr(const mxArray* obj, const string& propertyName) {
mxArray* mxh = mxGetProperty(obj,0,"self"); mxArray* mxh = mxGetProperty(obj,0, propertyName.c_str());
if (mxGetClassID(mxh) != mxUINT32OR64_CLASS || mxIsComplex(mxh) if (mxGetClassID(mxh) != mxUINT32OR64_CLASS || mxIsComplex(mxh)
|| mxGetM(mxh) != 1 || mxGetN(mxh) != 1) error( || mxGetM(mxh) != 1 || mxGetN(mxh) != 1) error(
"Parameter is not an Shared type."); "Parameter is not an Shared type.");

View File

@ -135,6 +135,21 @@ void generateIncludes(FileWriter& file, const string& class_name,
} }
/* ************************************************************************* */ /* ************************************************************************* */
string qualifiedName(const string& separator, const vector<string>& names, const string& finalName) {
string result;
if(!names.empty()) {
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);
} else if(!finalName.empty()) {
result = finalName;
}
return result;
}
/* ************************************************************************* */
} // \namespace wrap } // \namespace wrap

View File

@ -21,6 +21,9 @@
#include <exception> #include <exception>
#include <fstream> #include <fstream>
#include <sstream> #include <sstream>
#include <cstdint>
#include <string>
#include <boost/format.hpp>
#include "FileWriter.h" #include "FileWriter.h"
@ -28,44 +31,54 @@ namespace wrap {
class CantOpenFile : public std::exception { class CantOpenFile : public std::exception {
private: private:
std::string filename_; const std::string what_;
public: public:
CantOpenFile(const std::string& filename) : filename_(filename) {} CantOpenFile(const std::string& filename) : what_("Can't open file " + filename) {}
~CantOpenFile() throw() {} ~CantOpenFile() throw() {}
virtual const char* what() const throw() { virtual const char* what() const throw() { return what_.c_str(); }
return ("Can't open file " + filename_).c_str();
}
}; };
class ParseFailed : public std::exception { class ParseFailed : public std::exception {
private: private:
int length_; const std::string what_;
public: public:
ParseFailed(int length) : length_(length) {} ParseFailed(int length) : what_((boost::format("Parse failed at character [%d]")%(length-1)).str()) {}
~ParseFailed() throw() {} ~ParseFailed() throw() {}
virtual const char* what() const throw() { virtual const char* what() const throw() { return what_.c_str(); }
std::stringstream buf;
int len = length_+1;
buf << "Parse failed at character [" << len << "]";
return buf.str().c_str();
}
}; };
class DependencyMissing : public std::exception { class DependencyMissing : public std::exception {
private: private:
std::string dependency_; const std::string what_;
std::string location_;
public: public:
DependencyMissing(const std::string& dep, const std::string& loc) { DependencyMissing(const std::string& dep, const std::string& loc) :
dependency_ = dep; what_("Missing dependency " + dep + " in " + loc) {}
location_ = loc;
}
~DependencyMissing() throw() {} ~DependencyMissing() throw() {}
virtual const char* what() const throw() { virtual const char* what() const throw() { return what_.c_str(); }
return ("Missing dependency " + dependency_ + " in " + location_).c_str();
}
}; };
class DuplicateDefinition : public std::exception {
private:
const std::string what_;
public:
DuplicateDefinition(const std::string& name) :
what_("Duplicate definition of " + name) {}
~DuplicateDefinition() throw() {}
virtual const char* what() const throw() { return what_.c_str(); }
};
/** Special "magic number" passed into MATLAB constructor to indicate creating
* a MATLAB object from a shared_ptr allocated in C++
*/
static const uint64_t ptr_constructor_key =
(uint64_t('G') << 56) |
(uint64_t('T') << 48) |
(uint64_t('S') << 40) |
(uint64_t('A') << 32) |
(uint64_t('M') << 24) |
(uint64_t('p') << 16) |
(uint64_t('t') << 8) |
(uint64_t('r'));
/** /**
* read contents of a file into a std::string * read contents of a file into a std::string
@ -98,4 +111,10 @@ void generateUsingNamespace(FileWriter& file, const std::vector<std::string>& us
void generateIncludes(FileWriter& file, const std::string& class_name, void generateIncludes(FileWriter& file, const std::string& class_name,
const std::vector<std::string>& includes); const std::vector<std::string>& 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<std::string>& names, const std::string& finalName = "");
} // \namespace wrap } // \namespace wrap