Big refactor because methods now private member of Class

release/4.3a0
dellaert 2014-11-12 23:22:59 +01:00
parent 9933a1fbf4
commit 1ea0225030
11 changed files with 250 additions and 158 deletions

View File

@ -97,5 +97,22 @@ struct ArgumentList: public std::vector<Argument> {
const std::string& wrapperName, int id, bool staticMethod = false) const;
};
template<class T>
inline void verifyArguments(const std::vector<std::string>& validArgs,
const std::map<std::string, T>& vt) {
typedef typename std::map<std::string, T>::value_type NamedMethod;
BOOST_FOREACH(const NamedMethod& namedMethod, vt) {
const T& t = namedMethod.second;
BOOST_FOREACH(const ArgumentList& argList, t.argLists) {
BOOST_FOREACH(Argument arg, argList) {
std::string fullType = arg.type.qualifiedName("::");
if (find(validArgs.begin(), validArgs.end(), fullType)
== validArgs.end())
throw DependencyMissing(fullType, t.name);
}
}
}
}
} // \namespace wrap

View File

@ -324,6 +324,76 @@ vector<Class> Class::expandTemplate(const string& templateArg,
return result;
}
/* ************************************************************************* */
void Class::addMethod(bool verbose, bool is_const, const string& name,
const ArgumentList& args, const ReturnValue& retVal,
const string& templateArgName, const vector<Qualified>& templateArgValues) {
methods[name].addOverload(verbose, is_const, name, args, retVal);
}
/* ************************************************************************* */
void Class::erase_serialization() {
Methods::iterator it = methods.find("serializable");
if (it != methods.end()) {
#ifndef WRAP_DISABLE_SERIALIZE
isSerializable = true;
#else
// cout << "Ignoring serializable() flag in class " << name << endl;
#endif
methods.erase(it);
}
it = methods.find("serialize");
if (it != methods.end()) {
#ifndef WRAP_DISABLE_SERIALIZE
isSerializable = true;
hasSerialization = true;
#else
// cout << "Ignoring serialize() flag in class " << name << endl;
#endif
methods.erase(it);
}
}
/* ************************************************************************* */
void Class::verifyAll(vector<string>& validTypes, bool& hasSerialiable) const {
hasSerialiable |= isSerializable;
// verify all of the function arguments
//TODO:verifyArguments<ArgumentList>(validTypes, constructor.args_list);
verifyArguments<StaticMethod>(validTypes, static_methods);
verifyArguments<Method>(validTypes, methods);
// verify function return types
verifyReturnTypes<StaticMethod>(validTypes, static_methods);
verifyReturnTypes<Method>(validTypes, methods);
// verify parents
if (!qualifiedParent.empty()
&& find(validTypes.begin(), validTypes.end(),
qualifiedParent.qualifiedName("::")) == validTypes.end())
throw DependencyMissing(qualifiedParent.qualifiedName("::"),
qualifiedName("::"));
}
/* ************************************************************************* */
void Class::appendInheritedMethods(const Class& cls,
const vector<Class>& classes) {
if (!cls.qualifiedParent.empty()) {
// Find parent
BOOST_FOREACH(const Class& parent, classes) {
// We found a parent class for our parent, TODO improve !
if (parent.name == cls.qualifiedParent.name) {
methods.insert(parent.methods.begin(), parent.methods.end());
appendInheritedMethods(parent, classes);
}
}
}
}
/* ************************************************************************* */
string Class::getTypedef() const {
string result;

View File

@ -31,57 +31,87 @@
namespace wrap {
/// Class has name, constructors, methods
struct Class : public Qualified {
class Class: public Qualified {
typedef std::map<std::string, Method> Methods;
Methods methods; ///< Class methods
public:
typedef std::map<std::string, StaticMethod> StaticMethods;
// Then the instance variables are set directly by the Module constructor
std::vector<std::string> templateArgs; ///< Template arguments
std::string typedefName; ///< The name to typedef *from*, if this class is actually a typedef, i.e. typedef [typedefName] [name]
bool isVirtual; ///< Whether the class is part of a virtual inheritance chain
bool isSerializable; ///< Whether we can use boost.serialization to serialize the class - creates exports
bool hasSerialization; ///< Whether we should create the serialization functions
Qualified qualifiedParent; ///< The *single* parent
StaticMethods static_methods; ///< Static methods
Constructor constructor; ///< Class constructors
Deconstructor deconstructor; ///< Deconstructor to deallocate C++ object
bool verbose_; ///< verbose flag
/// Constructor creates an empty class
Class(bool verbose = true) :
isVirtual(false), isSerializable(false), hasSerialization(false), deconstructor(
verbose), verbose_(verbose) {
}
// Then the instance variables are set directly by the Module constructor
std::vector<std::string> templateArgs; ///< Template arguments
std::string typedefName; ///< The name to typedef *from*, if this class is actually a typedef, i.e. typedef [typedefName] [name]
bool isVirtual; ///< Whether the class is part of a virtual inheritance chain
bool isSerializable; ///< Whether we can use boost.serialization to serialize the class - creates exports
bool hasSerialization; ///< Whether we should create the serialization functions
Qualified qualifiedParent; ///< The *single* parent
Methods methods; ///< Class methods
StaticMethods static_methods; ///< Static methods
Constructor constructor; ///< Class constructors
Deconstructor deconstructor; ///< Deconstructor to deallocate C++ object
bool verbose_; ///< verbose flag
size_t nrMethods() const { return methods.size(); }
Method& method(const std::string& name) { return methods.at(name); }
bool exists(const std::string& name) const { return methods.find(name) != methods.end(); }
// And finally MATLAB code is emitted, methods below called by Module::matlab_code
void matlab_proxy(const std::string& toolboxPath, const std::string& wrapperName, const TypeAttributesTable& typeAttributes,
FileWriter& wrapperFile, std::vector<std::string>& functionNames) const; ///< emit proxy class
void matlab_proxy(const std::string& toolboxPath,
const std::string& wrapperName, const TypeAttributesTable& typeAttributes,
FileWriter& wrapperFile, std::vector<std::string>& functionNames) const; ///< emit proxy class
Class expandTemplate(const std::string& templateArg,
const Qualified& instantiation,
const Qualified& expandedClass) const;
const Qualified& instantiation, const Qualified& expandedClass) const;
std::vector<Class> expandTemplate(const std::string& templateArg,
const std::vector<Qualified >& instantiations) const;
const std::vector<Qualified>& instantiations) const;
// The typedef line for this class, if this class is a typedef, otherwise returns an empty string.
/// Add potentially overloaded, potentially templated method
void addMethod(bool verbose, bool is_const, const std::string& name,
const ArgumentList& args, const ReturnValue& retVal,
const std::string& templateArgName,
const std::vector<Qualified>& templateArgValues);
/// Post-process classes for serialization markers
void erase_serialization(); // non-const !
/// verify all of the function arguments
void verifyAll(std::vector<std::string>& functionNames,
bool& hasSerialiable) const;
void appendInheritedMethods(const Class& cls,
const std::vector<Class>& classes);
/// The typedef line for this class, if this class is a typedef, otherwise returns an empty string.
std::string getTypedef() const;
// Returns the string for an export flag
/// Returns the string for an export flag
std::string getSerializationExport() const;
// Creates a member function that performs serialization
/// Creates a member function that performs serialization
void serialization_fragments(FileWriter& proxyFile, FileWriter& wrapperFile,
const std::string& wrapperName, std::vector<std::string>& functionNames) const;
const std::string& wrapperName,
std::vector<std::string>& functionNames) const;
// Creates a static member function that performs deserialization
/// Creates a static member function that performs deserialization
void deserialization_fragments(FileWriter& proxyFile, FileWriter& wrapperFile,
const std::string& wrapperName, std::vector<std::string>& functionNames) const;
const std::string& wrapperName,
std::vector<std::string>& functionNames) const;
private:
void pointer_constructor_fragments(FileWriter& proxyFile, FileWriter& wrapperFile, const std::string& wrapperName, std::vector<std::string>& functionNames) const;
void comment_fragment(FileWriter& proxyFile) const;
void pointer_constructor_fragments(FileWriter& proxyFile,
FileWriter& wrapperFile, const std::string& wrapperName,
std::vector<std::string>& functionNames) const;
void comment_fragment(FileWriter& proxyFile) const;
};
} // \namespace wrap

View File

@ -31,12 +31,13 @@ using namespace wrap;
/* ************************************************************************* */
void Method::addOverload(bool verbose, bool is_const, const std::string& name,
const ArgumentList& args, const ReturnValue& retVal) {
if (name.empty())
this->name = name;
else if (this->name != name)
#ifdef ADD_OVERLOAD_CHECK_NAME
if (!name.empty() && this->name != name)
throw std::runtime_error(
"Method::addOverload: tried to add overload with name " + name
+ " instead of expected " + this->name);
#endif
this->name = name;
this->verbose_ = verbose;
this->is_const_ = is_const;
this->name = name;

View File

@ -254,18 +254,17 @@ void Module::parseMarkup(const std::string& data) {
// gtsam::Values retract(const gtsam::VectorValues& delta) const;
string methodName;
bool isConst, isConst0 = false;
vector<Qualified> methodInstantiations;
Rule method_p =
!templateArgValues_p
[assign_a(methodInstantiations,templateArgValues)][clear_a(templateArgValues)] >>
!templateArgValues_p >>
(returnValue_p >> methodName_p[assign_a(methodName)] >>
'(' >> argumentList_p >> ')' >>
!str_p("const")[assign_a(isConst,true)] >> ';' >> *comments_p)
[bl::bind(&Method::addOverload,
bl::var(cls.methods)[bl::var(methodName)], verbose,
bl::var(isConst), bl::var(methodName), bl::var(args), bl::var(retVal))]
[bl::bind(&Class::addMethod, bl::var(cls), verbose, bl::var(isConst),
bl::var(methodName), bl::var(args), bl::var(retVal),
bl::var(templateArgName), bl::var(templateArgValues))]
[assign_a(retVal,retVal0)]
[clear_a(args)]
[clear_a(templateArgValues)]
[assign_a(isConst,isConst0)];
Rule staticMethodName_p = lexeme_d[(upper_p | lower_p) >> *(alnum_p | '_')];
@ -388,69 +387,14 @@ void Module::parseMarkup(const std::string& data) {
}
// Post-process classes for serialization markers
BOOST_FOREACH(Class& cls, classes) {
Class::Methods::iterator serializable_it = cls.methods.find("serializable");
if (serializable_it != cls.methods.end()) {
#ifndef WRAP_DISABLE_SERIALIZE
cls.isSerializable = true;
#else
// cout << "Ignoring serializable() flag in class " << cls.name << endl;
#endif
cls.methods.erase(serializable_it);
}
Class::Methods::iterator serialize_it = cls.methods.find("serialize");
if (serialize_it != cls.methods.end()) {
#ifndef WRAP_DISABLE_SERIALIZE
cls.isSerializable = true;
cls.hasSerialization= true;
#else
// cout << "Ignoring serialize() flag in class " << cls.name << endl;
#endif
cls.methods.erase(serialize_it);
}
}
BOOST_FOREACH(Class& cls, classes)
cls.erase_serialization();
// Explicitly add methods to the classes from parents so it shows in documentation
BOOST_FOREACH(Class& cls, classes)
{
map<string, Method> inhereted = appendInheretedMethods(cls, classes);
cls.methods.insert(inhereted.begin(), inhereted.end());
}
cls.appendInheritedMethods(cls, classes);
}
/* ************************************************************************* */
template<class T>
void verifyArguments(const vector<string>& validArgs, const map<string,T>& vt) {
typedef typename map<string,T>::value_type Name_Method;
BOOST_FOREACH(const Name_Method& name_method, vt) {
const T& t = name_method.second;
BOOST_FOREACH(const ArgumentList& argList, t.argLists) {
BOOST_FOREACH(Argument arg, argList) {
string fullType = arg.type.qualifiedName("::");
if(find(validArgs.begin(), validArgs.end(), fullType)
== validArgs.end())
throw DependencyMissing(fullType, t.name);
}
}
}
}
/* ************************************************************************* */
template<class T>
void verifyReturnTypes(const vector<string>& validtypes,
const map<string, T>& vt) {
typedef typename map<string, T>::value_type Name_Method;
BOOST_FOREACH(const Name_Method& name_method, vt) {
const T& t = name_method.second;
BOOST_FOREACH(const ReturnValue& retval, t.returnVals) {
retval.type1.verify(validtypes, t.name);
if (retval.isPair)
retval.type2.verify(validtypes, t.name);
}
}
}
/* ************************************************************************* */
void Module::generateIncludes(FileWriter& file) const {
@ -486,22 +430,8 @@ void Module::matlab_code(const string& toolboxPath, const string& headerPath) co
verifyReturnTypes<GlobalFunction>(validTypes, global_functions);
bool hasSerialiable = false;
BOOST_FOREACH(const Class& cls, expandedClasses) {
hasSerialiable |= cls.isSerializable;
// verify all of the function arguments
//TODO:verifyArguments<ArgumentList>(validTypes, cls.constructor.args_list);
verifyArguments<StaticMethod>(validTypes, cls.static_methods);
verifyArguments<Method>(validTypes, cls.methods);
// verify function return types
verifyReturnTypes<StaticMethod>(validTypes, cls.static_methods);
verifyReturnTypes<Method>(validTypes, cls.methods);
// verify parents
Qualified parent = cls.qualifiedParent;
if(!parent.empty() && std::find(validTypes.begin(), validTypes.end(), parent.qualifiedName("::")) == validTypes.end())
throw DependencyMissing(parent.qualifiedName("::"), cls.qualifiedName("::"));
}
BOOST_FOREACH(const Class& cls, expandedClasses)
cls.verifyAll(validTypes,hasSerialiable);
// Create type attributes table and check validity
TypeAttributesTable typeAttributes;
@ -568,28 +498,7 @@ void Module::matlab_code(const string& toolboxPath, const string& headerPath) co
wrapperFile.emit(true);
}
/* ************************************************************************* */
map<string, Method> Module::appendInheretedMethods(const Class& cls, const vector<Class>& classes)
{
map<string, Method> methods;
if(!cls.qualifiedParent.empty())
{
//Find Class
BOOST_FOREACH(const Class& parent, classes) {
//We found the class for our parent
if(parent.name == cls.qualifiedParent.name)
{
Methods inhereted = appendInheretedMethods(parent, classes);
methods.insert(inhereted.begin(), inhereted.end());
}
}
} else {
methods.insert(cls.methods.begin(), cls.methods.end());
}
return methods;
}
/* ************************************************************************* */
void Module::finish_wrapper(FileWriter& file, const std::vector<std::string>& functionNames) const {
file.oss << "void mexFunction(int nargout, mxArray *out[], int nargin, const mxArray *in[])\n";

View File

@ -53,9 +53,6 @@ struct Module {
/// Dummy constructor that does no parsing - use only for testing
Module(const std::string& moduleName, bool enable_verbose=true);
//Recursive method to append all methods inhereted from parent classes
std::map<std::string, Method> appendInheretedMethods(const Class& cls, const std::vector<Class>& classes);
/// MATLAB code generation:
void matlab_code(
const std::string& path,

View File

@ -97,4 +97,18 @@ struct ReturnValue {
void emit_matlab(FileWriter& proxyFile) const;
};
template<class T>
inline void verifyReturnTypes(const std::vector<std::string>& validtypes,
const std::map<std::string, T>& vt) {
typedef typename std::map<std::string, T>::value_type NamedMethod;
BOOST_FOREACH(const NamedMethod& namedMethod, vt) {
const T& t = namedMethod.second;
BOOST_FOREACH(const ReturnValue& retval, t.returnVals) {
retval.type1.verify(validtypes, t.name);
if (retval.isPair)
retval.type2.verify(validtypes, t.name);
}
}
}
} // \namespace wrap

View File

@ -28,7 +28,7 @@
namespace wrap {
// Forward declarations
struct Class;
class Class;
/** Attributes about valid classes, both for classes defined in this module and
* also those forward-declared from others. At the moment this only contains
@ -52,4 +52,4 @@ public:
void checkValidity(const std::vector<Class>& classes) const;
};
}
}

51
wrap/tests/testClass.cpp Normal file
View File

@ -0,0 +1,51 @@
/* ----------------------------------------------------------------------------
* GTSAM Copyright 2010, Georgia Tech Research Corporation,
* Atlanta, Georgia 30332-0415
* All Rights Reserved
* Authors: Frank Dellaert, et al. (see THANKS for the full author list)
* See LICENSE for the license information
* -------------------------------------------------------------------------- */
/**
* @file testClass.cpp
* @brief Unit test for Class class
* @author Frank Dellaert
* @date Nov 12, 2014
**/
#include <wrap/Class.h>
#include <CppUnitLite/TestHarness.h>
#include <iostream>
using namespace std;
using namespace wrap;
/* ************************************************************************* */
// Constructor
TEST( Class, Constructor ) {
Class cls;
}
/* ************************************************************************* */
// addMethodOverloads
TEST( Class, addMethod ) {
Class cls;
bool verbose=true, is_const=true;
const string name;
ArgumentList args;
const ReturnValue retVal;
const string templateArgName;
vector<Qualified> templateArgValues;
cls.addMethod(verbose, is_const, name, args, retVal, templateArgName,
templateArgValues);
}
/* ************************************************************************* */
int main() {
TestResult tr;
return TestRegistry::runAllTests(tr);
}
/* ************************************************************************* */

View File

@ -73,7 +73,7 @@ TEST( wrap, check_exception ) {
}
/* ************************************************************************* */
TEST( wrap, small_parse ) {
TEST( wrap, Small ) {
string moduleName("gtsam");
Module module(moduleName, true);
@ -92,11 +92,11 @@ TEST( wrap, small_parse ) {
EXPECT(assert_equal("Point2", cls.name));
EXPECT(!cls.isVirtual);
EXPECT(cls.namespaces.empty());
LONGS_EQUAL(3, cls.methods.size());
LONGS_EQUAL(3, cls.nrMethods());
LONGS_EQUAL(1, cls.static_methods.size());
// Method 1
Method m1 = cls.methods.at("x");
Method m1 = cls.method("x");
EXPECT(assert_equal("x", m1.name));
EXPECT(m1.is_const_);
LONGS_EQUAL(1, m1.argLists.size());
@ -109,7 +109,7 @@ TEST( wrap, small_parse ) {
EXPECT_LONGS_EQUAL(ReturnType::BASIS, rv1.type1.category);
// Method 2
Method m2 = cls.methods.at("returnMatrix");
Method m2 = cls.method("returnMatrix");
EXPECT(assert_equal("returnMatrix", m2.name));
EXPECT(m2.is_const_);
LONGS_EQUAL(1, m2.argLists.size());
@ -122,7 +122,7 @@ TEST( wrap, small_parse ) {
EXPECT_LONGS_EQUAL(ReturnType::EIGEN, rv2.type1.category);
// Method 3
Method m3 = cls.methods.at("returnPoint2");
Method m3 = cls.method("returnPoint2");
EXPECT(assert_equal("returnPoint2", m3.name));
EXPECT(m3.is_const_);
LONGS_EQUAL(1, m3.argLists.size());
@ -150,7 +150,7 @@ TEST( wrap, small_parse ) {
}
/* ************************************************************************* */
TEST( wrap, parse_geometry ) {
TEST( wrap, Geometry ) {
string markup_header_path = topdir + "/wrap/tests";
Module module(markup_header_path.c_str(), "geometry",enable_verbose);
EXPECT_LONGS_EQUAL(7, module.classes.size());
@ -189,12 +189,12 @@ TEST( wrap, parse_geometry ) {
Class cls = module.classes.at(0);
EXPECT(assert_equal("Point2", cls.name));
EXPECT_LONGS_EQUAL(2, cls.constructor.args_list.size());
EXPECT_LONGS_EQUAL(7, cls.methods.size());
EXPECT_LONGS_EQUAL(7, cls.nrMethods());
{
// char returnChar() const;
CHECK(cls.methods.find("returnChar") != cls.methods.end());
Method m1 = cls.methods.find("returnChar")->second;
CHECK(cls.exists("returnChar"));
Method m1 = cls.method("returnChar");
LONGS_EQUAL(1, m1.returnVals.size());
EXPECT(assert_equal("char", m1.returnVals.front().type1.name));
EXPECT_LONGS_EQUAL(ReturnType::BASIS, m1.returnVals.front().type1.category);
@ -207,8 +207,8 @@ TEST( wrap, parse_geometry ) {
{
// VectorNotEigen vectorConfusion();
CHECK(cls.methods.find("vectorConfusion") != cls.methods.end());
Method m1 = cls.methods.find("vectorConfusion")->second;
CHECK(cls.exists("vectorConfusion"));
Method m1 = cls.method("vectorConfusion");
LONGS_EQUAL(1, m1.returnVals.size());
EXPECT(assert_equal("VectorNotEigen", m1.returnVals.front().type1.name));
EXPECT_LONGS_EQUAL(ReturnType::CLASS, m1.returnVals.front().type1.category);
@ -234,7 +234,7 @@ TEST( wrap, parse_geometry ) {
Class cls = module.classes.at(1);
EXPECT(assert_equal("Point3", cls.name));
EXPECT_LONGS_EQUAL(1, cls.constructor.args_list.size());
EXPECT_LONGS_EQUAL(1, cls.methods.size());
EXPECT_LONGS_EQUAL(1, cls.nrMethods());
EXPECT_LONGS_EQUAL(2, cls.static_methods.size());
EXPECT_LONGS_EQUAL(0, cls.namespaces.size());
@ -250,8 +250,8 @@ TEST( wrap, parse_geometry ) {
EXPECT(assert_equal("x", a1.name));
// check method
CHECK(cls.methods.find("norm") != cls.methods.end());
Method m1 = cls.methods.find("norm")->second;
CHECK(cls.exists("norm"));
Method m1 = cls.method("norm");
LONGS_EQUAL(1, m1.returnVals.size());
EXPECT(assert_equal("double", m1.returnVals.front().type1.name));
EXPECT_LONGS_EQUAL(ReturnType::BASIS, m1.returnVals.front().type1.category);
@ -271,13 +271,13 @@ TEST( wrap, parse_geometry ) {
{
Class testCls = module.classes.at(2);
EXPECT_LONGS_EQUAL( 2, testCls.constructor.args_list.size());
EXPECT_LONGS_EQUAL(19, testCls.methods.size());
EXPECT_LONGS_EQUAL(19, testCls.nrMethods());
EXPECT_LONGS_EQUAL( 0, testCls.static_methods.size());
EXPECT_LONGS_EQUAL( 0, testCls.namespaces.size());
// function to parse: pair<Vector,Matrix> return_pair (Vector v, Matrix A) const;
CHECK(testCls.methods.find("return_pair") != testCls.methods.end());
Method m2 = testCls.methods.find("return_pair")->second;
CHECK(testCls.exists("return_pair"));
Method m2 = testCls.method("return_pair");
LONGS_EQUAL(1, m2.returnVals.size());
EXPECT(m2.returnVals.front().isPair);
EXPECT_LONGS_EQUAL(ReturnType::EIGEN, m2.returnVals.front().type1.category);
@ -287,8 +287,8 @@ TEST( wrap, parse_geometry ) {
// checking pointer args and return values
// pair<Test*,Test*> return_ptrs (Test* p1, Test* p2) const;
CHECK(testCls.methods.find("return_ptrs") != testCls.methods.end());
Method m3 = testCls.methods.find("return_ptrs")->second;
CHECK(testCls.exists("return_ptrs"));
Method m3 = testCls.method("return_ptrs");
LONGS_EQUAL(1, m3.argLists.size());
ArgumentList args = m3.argLists.front();
LONGS_EQUAL(2, args.size());

View File

@ -18,17 +18,20 @@
#pragma once
#include "FileWriter.h"
#include <boost/format.hpp>
#include <boost/foreach.hpp>
#include <string>
#include <vector>
#include <exception>
#include <fstream>
#include <sstream>
//#include <cstdint> // on Linux GCC: fails with error regarding needing C++0x std flags
//#include <cinttypes> // same failure as above
#include <stdint.h> // works on Linux GCC
#include <string>
#include <boost/format.hpp>
#include "FileWriter.h"
namespace wrap {