diff --git a/wrap/Class.cpp b/wrap/Class.cpp index 6e415065d..e62e31bc1 100644 --- a/wrap/Class.cpp +++ b/wrap/Class.cpp @@ -28,6 +28,7 @@ #include #include #include +#include #include // std::ostream_iterator //#include // on Linux GCC: fails with error regarding needing C++0x std flags //#include // same failure as above @@ -314,6 +315,25 @@ vector Class::expandTemplate(Str templateArg, return result; } +/* ************************************************************************* */ +vector Class::expandTemplate(Str templateArg, + const vector& integers) const { + vector result; + BOOST_FOREACH(int i, integers) { + Qualified expandedClass = (Qualified) (*this); + stringstream ss; ss << i; + string instName = ss.str(); + expandedClass.expand(instName); + const TemplateSubstitution ts(templateArg, instName, expandedClass); + Class inst = expandTemplate(ts); + inst.name_ = expandedClass.name(); + inst.templateArgs.clear(); + inst.typedefName = qualifiedName("::") + "<" + instName + ">"; + result.push_back(inst); + } + return result; +} + /* ************************************************************************* */ void Class::addMethod(bool verbose, bool is_const, Str methodName, const ArgumentList& argumentList, const ReturnValue& returnValue, diff --git a/wrap/Class.h b/wrap/Class.h index f4c687eca..2f7457f06 100644 --- a/wrap/Class.h +++ b/wrap/Class.h @@ -106,6 +106,10 @@ public: std::vector expandTemplate(Str templateArg, const std::vector& instantiations) const; + // Create new classes with integer template arguments + std::vector expandTemplate(Str templateArg, + const std::vector& integers) const; + /// Add potentially overloaded, potentially templated method void addMethod(bool verbose, bool is_const, Str methodName, const ArgumentList& argumentList, const ReturnValue& returnValue, diff --git a/wrap/Module.cpp b/wrap/Module.cpp index 092c732f7..9d505a525 100644 --- a/wrap/Module.cpp +++ b/wrap/Module.cpp @@ -47,15 +47,17 @@ namespace fs = boost::filesystem; // If a number of template arguments were given, generate a number of expanded // class names, e.g., PriorFactor -> PriorFactorPose2, and add those classes static void handle_possible_template(vector& classes, const Class& cls, - const vector& instantiations) { - if (cls.templateArgs.empty() || instantiations.empty()) { + const Template& t) { + if (cls.templateArgs.empty() || t.empty()) { classes.push_back(cls); } else { if (cls.templateArgs.size() != 1) throw std::runtime_error( "In-line template instantiations only handle a single template argument"); - vector classInstantiations = // - cls.expandTemplate(cls.templateArgs.front(), instantiations); + string arg = cls.templateArgs.front(); + vector classInstantiations = + (t.nrValues() > 0) ? cls.expandTemplate(arg, t.argValues()) : + cls.expandTemplate(arg, t.intList()); BOOST_FOREACH(const Class& c, classInstantiations) classes.push_back(c); } @@ -107,7 +109,7 @@ void Module::parseMarkup(const std::string& data) { Rule class_p = class_g // [assign_a(cls.namespaces_, namespaces)] [bl::bind(&handle_possible_template, bl::var(classes), bl::var(cls), - bl::var(classTemplate.argValues()))] + bl::var(classTemplate))] [clear_a(classTemplate)] // [assign_a(cls,cls0)]; diff --git a/wrap/Template.h b/wrap/Template.h index 5a64412ed..991c6c883 100644 --- a/wrap/Template.h +++ b/wrap/Template.h @@ -26,6 +26,7 @@ namespace wrap { class Template { std::string argName_; std::vector argValues_; + std::vector intList_; friend struct TemplateGrammar; public: /// The only way to get values into a Template is via our friendly Grammar @@ -34,13 +35,20 @@ public: void clear() { argName_.clear(); argValues_.clear(); + intList_.clear(); } const std::string& argName() const { return argName_; } + const std::vector& intList() const { + return intList_; + } const std::vector& argValues() const { return argValues_; } + bool empty() const { + return argValues_.empty() && intList_.empty(); + } size_t nrValues() const { return argValues_.size(); } @@ -53,16 +61,52 @@ public: }; +/* ************************************************************************* */ +// http://boost-spirit.com/distrib/spirit_1_8_2/libs/spirit/doc/grammar.html +struct IntListGrammar: public classic::grammar { + + typedef std::vector IntList; + IntList& result_; ///< successful parse will be placed in here + + /// Construct type grammar and specify where result is placed + IntListGrammar(IntList& result) : + result_(result) { + } + + /// Definition of type grammar + template + struct definition { + + classic::rule integer_p, intList_p; + + definition(IntListGrammar const& self) { + using namespace classic; + + integer_p = int_p[push_back_a(self.result_)]; + + intList_p = '{' >> !integer_p >> *(',' >> integer_p) >> '}'; + } + + classic::rule const& start() const { + return intList_p; + } + + }; +}; +// IntListGrammar + /* ************************************************************************* */ // http://boost-spirit.com/distrib/spirit_1_8_2/libs/spirit/doc/grammar.html struct TemplateGrammar: public classic::grammar { Template& result_; ///< successful parse will be placed in here TypeListGrammar<'{', '}'> argValues_g; ///< TypeList parser + IntListGrammar intList_g; ///< TypeList parser /// Construct type grammar and specify where result is placed TemplateGrammar(Template& result) : - result_(result), argValues_g(result.argValues_) { + result_(result), argValues_g(result.argValues_), // + intList_g(result.intList_) { } /// Definition of type grammar @@ -76,7 +120,7 @@ struct TemplateGrammar: public classic::grammar { using classic::assign_a; templateArgValues_p = (str_p("template") >> '<' >> (BasicRules::name_p)[assign_a(self.result_.argName_)] - >> '=' >> self.argValues_g >> '>'); + >> '=' >> (self.argValues_g | self.intList_g) >> '>'); } classic::rule const& start() const { diff --git a/wrap/tests/geometry.h b/wrap/tests/geometry.h index 69bc7e3be..376e39b62 100644 --- a/wrap/tests/geometry.h +++ b/wrap/tests/geometry.h @@ -127,6 +127,12 @@ class MyFactor { // and a typedef specializing it typedef MyFactor MyFactorPosePoint2; +// A class with integer template arguments +template +class MyVector { + MyVector(); +}; + // comments at the end! // even more comments at the end! diff --git a/wrap/tests/testClass.cpp b/wrap/tests/testClass.cpp index a133e15ac..3d8d79b33 100644 --- a/wrap/tests/testClass.cpp +++ b/wrap/tests/testClass.cpp @@ -221,6 +221,29 @@ TEST( Class, TemplateSubstition ) { } +//****************************************************************************** +TEST( Class, TemplateSubstitionIntList ) { + + using classic::space_p; + + // Create type grammar that will place result in cls + Class cls; + Template t; + ClassGrammar g(cls, t); + + string markup(string("template" + "class Point2 {" + " void myMethod(Matrix A) const;" + "};")); + + EXPECT(parse(markup.c_str(), g, space_p).full); + + vector classes = cls.expandTemplate(t.argName(), t.intList()); + + // check the number of new classes is 2 + EXPECT_LONGS_EQUAL(2, classes.size()); +} + //****************************************************************************** TEST(Class, Template) { diff --git a/wrap/tests/testTemplate.cpp b/wrap/tests/testTemplate.cpp index 37cb95205..eed144677 100644 --- a/wrap/tests/testTemplate.cpp +++ b/wrap/tests/testTemplate.cpp @@ -47,6 +47,15 @@ TEST( Template, grammar ) { EXPECT(actual[2]==Qualified("Vector",Qualified::EIGEN)); EXPECT(actual[3]==Qualified("Matrix",Qualified::EIGEN)); actual.clear(); + + EXPECT(parse("template", g, space_p).full); + EXPECT_LONGS_EQUAL(4, actual.intList().size()); + EXPECT(actual.argName()=="N"); + EXPECT_LONGS_EQUAL(1,actual.intList()[0]); + EXPECT_LONGS_EQUAL(2,actual.intList()[1]); + EXPECT_LONGS_EQUAL(3,actual.intList()[2]); + EXPECT_LONGS_EQUAL(4,actual.intList()[3]); + actual.clear(); } //****************************************************************************** diff --git a/wrap/tests/testWrap.cpp b/wrap/tests/testWrap.cpp index c03c40444..d8d952413 100644 --- a/wrap/tests/testWrap.cpp +++ b/wrap/tests/testWrap.cpp @@ -144,7 +144,7 @@ TEST( wrap, Small ) { 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()); + EXPECT_LONGS_EQUAL(9, module.classes.size()); // forward declarations LONGS_EQUAL(2, module.forward_declarations.size()); @@ -155,7 +155,7 @@ TEST( wrap, Geometry ) { strvec exp_includes; exp_includes += "folder/path/to/Test.h"; EXPECT(assert_equal(exp_includes, module.includes)); - LONGS_EQUAL(7, module.classes.size()); + LONGS_EQUAL(9, module.classes.size()); // Key for ReturnType::return_category // CLASS = 1,