Squashed 'wrap/' changes from b0eb968f2..d19cda546
d19cda546 Merge pull request #36 from borglab/fix/shared-ptr-property 13ef2485c Merge pull request #37 from borglab/feature/multiple-templates f3f40b375 add support for multiple instantiated templates 4f33353ef support for templated return types 1244045c2 cleaned up tests and added test for Pybind property shared pointer 0f3fbc428 add support for pointers as properties, and update docs 9974a73ec Merge pull request #35 from borglab/feature/docs e9c52421d Added DOCS with info about wrapping structure 627154f9f fix call to superclass init 8a4e61ead added more docs and fixed typo for holder_type b1bdec933 added docstrings to interface_parser and took care of all the errors and warnings git-subtree-dir: wrap git-subtree-split: d19cda5467f8b5cb8d4f571d8735ede328dae02drelease/4.3a0
parent
f52b09660e
commit
55dade0b8e
|
@ -0,0 +1,167 @@
|
|||
## Wrap Module Definition
|
||||
|
||||
### Important
|
||||
|
||||
The python wrapper supports keyword arguments for functions/methods. Hence, the argument names matter. An implementation restriction is that in overloaded methods or functions, arguments of different types *have* to have different names.
|
||||
|
||||
### Requirements
|
||||
|
||||
- Classes must start with an uppercase letter.
|
||||
- The wrapper can wrap a typedef, e.g. `typedef TemplatedClass<Arg> EasyName;`.
|
||||
|
||||
- Only one Method/Constructor per line, though methods/constructors can extend across multiple lines.
|
||||
|
||||
- Methods can return
|
||||
- Eigen types: `Matrix`, `Vector`.
|
||||
- C/C++ basic types: `string`, `bool`, `size_t`, `int`, `double`, `char`, `unsigned char`.
|
||||
- `void`
|
||||
- Any class with which be copied with `boost::make_shared()`.
|
||||
- `boost::shared_ptr` of any object type.
|
||||
|
||||
- Constructors
|
||||
- Overloads are supported, but arguments of different types *have* to have different names.
|
||||
- A class with no constructors can be returned from other functions but not allocated directly in MATLAB.
|
||||
|
||||
- Methods
|
||||
- Constness has no effect.
|
||||
- Specify by-value (not reference) return types, even if C++ method returns reference.
|
||||
- Must start with a letter (upper or lowercase).
|
||||
- Overloads are supported.
|
||||
|
||||
- Static methods
|
||||
- Must start with a letter (upper or lowercase) and use the "static" keyword, e.g. `static void func()`.
|
||||
- The first letter will be made uppercase in the generated MATLAB interface.
|
||||
- Overloads are supported, but arguments of different types *have* to have different names.
|
||||
|
||||
- Arguments to functions can be any of
|
||||
- Eigen types: `Matrix`, `Vector`.
|
||||
- Eigen types and classes as an optionally const reference.
|
||||
- C/C++ basic types: `string`, `bool`, `size_t`, `size_t`, `double`, `char`, `unsigned char`.
|
||||
- Any class with which be copied with `boost::make_shared()` (except Eigen).
|
||||
- `boost::shared_ptr` of any object type (except Eigen).
|
||||
|
||||
- Properties or Variables
|
||||
- You can specify class variables in the interface file as long as they are in the `public` scope, e.g.
|
||||
|
||||
```cpp
|
||||
class Sample {
|
||||
double seed;
|
||||
};
|
||||
```
|
||||
|
||||
- Class variables are read-write so they can be updated directly in Python.
|
||||
|
||||
- Pointer types
|
||||
- To declare a pointer type (including shared pointers), simply add an asterisk (i.e. `*`) to the class name.
|
||||
- E.g. `gtsam::noiseModel::Base*` to define the wrapping for the `Base` noise model shared pointer.
|
||||
|
||||
- Comments can use either C++ or C style, with multiple lines.
|
||||
|
||||
- Namespace definitions
|
||||
- Names of namespaces must start with a lowercase letter.
|
||||
- Start a namespace with `namespace example_ns {`, where `example_ns` is the namespace name.
|
||||
- End a namespace with exactly `}`
|
||||
- Namespaces can be nested.
|
||||
|
||||
- Namespace usage
|
||||
- Namespaces can be specified for classes in arguments and return values.
|
||||
- In each case, the namespace must be fully specified, e.g., `namespace1::namespace2::ClassName`.
|
||||
|
||||
- Includes in C++ wrappers
|
||||
- All includes will be collected and added in a single file.
|
||||
- All namespaces must have angle brackets, e.g. `#include <path>`.
|
||||
- No default includes will be added.
|
||||
|
||||
- Global/Namespace functions
|
||||
- Functions specified outside of a class are **global**.
|
||||
- Can be overloaded with different arguments.
|
||||
- Can have multiple functions of the same name in different namespaces.
|
||||
|
||||
- Using classes defined in other modules
|
||||
- If you are using a class `OtherClass` not wrapped in an interface file, add `class OtherClass;` as a forward declaration to avoid a dependency error.
|
||||
|
||||
- Virtual inheritance
|
||||
- Specify fully-qualified base classes, i.e. `virtual class Derived : ns::Base {` where `ns` is the namespace.
|
||||
- Mark with `virtual` keyword, e.g. `virtual class Base {`, and also `virtual class Derived : ns::Base {`.
|
||||
- Forward declarations must also be marked virtual, e.g. `virtual class ns::Base;` and
|
||||
also `virtual class ns::Derived;`.
|
||||
- Pure virtual (abstract) classes should list no constructors in the interface file.
|
||||
- Virtual classes must have a `clone()` function in C++ (though it does not have to be included
|
||||
in the interface file). `clone()` will be called whenever an object copy is needed, instead
|
||||
of using the copy constructor (which is used for non-virtual objects).
|
||||
- Signature of clone function - `clone()` will be called virtually, so must appear at least at the top of the inheritance tree
|
||||
|
||||
```cpp
|
||||
virtual boost::shared_ptr<CLASS_NAME> clone() const;
|
||||
```
|
||||
|
||||
- Class Templates
|
||||
- Basic templates are supported either with an explicit list of types to instantiate,
|
||||
e.g.
|
||||
|
||||
```cpp
|
||||
template<T = {gtsam::Pose2, gtsam::Rot2, gtsam::Point3}> class Class1 { ... };
|
||||
```
|
||||
|
||||
or with typedefs, e.g.
|
||||
|
||||
```cpp
|
||||
template<T, U> class Class2 { ... };
|
||||
typedef Class2<Type1, Type2> MyInstantiatedClass;
|
||||
```
|
||||
|
||||
- In the class definition, appearances of the template argument(s) will be replaced with their
|
||||
instantiated types, e.g. `void setValue(const T& value);`.
|
||||
- To refer to the instantiation of the template class itself, use `This`, i.e. `static This Create();`.
|
||||
- To create new instantiations in other modules, you must copy-and-paste the whole class definition
|
||||
into the new module, but use only your new instantiation types.
|
||||
- When forward-declaring template instantiations, use the generated/typedefed name, e.g.
|
||||
|
||||
```cpp
|
||||
class gtsam::Class1Pose2;
|
||||
class gtsam::MyInstantiatedClass;
|
||||
```
|
||||
|
||||
- `Boost.serialization` within the wrapper:
|
||||
- You need to mark classes as being serializable in the markup file (see `gtsam.i` for examples).
|
||||
- There are two options currently, depending on the class. To "mark" a class as serializable,
|
||||
add a function with a particular signature so that `wrap` will catch it.
|
||||
- Add `void serialize()` to a class to create serialization functions for a class.
|
||||
Adding this flag subsumes the `serializable()` flag below.
|
||||
|
||||
Requirements:
|
||||
- A default constructor must be publicly accessible.
|
||||
- Must not be an abstract base class.
|
||||
- The class must have an actual boost.serialization `serialize()` function.
|
||||
|
||||
- Add `void serializable()` to a class if you only want the class to be serialized as a
|
||||
part of a container (such as `noiseModel`). This version does not require a publicly
|
||||
accessible default constructor.
|
||||
|
||||
- Forward declarations and class definitions for **Pybind**:
|
||||
- Need to specify the base class (both this forward class and base class are declared in an external Pybind header)
|
||||
This is so that Pybind can generate proper inheritance.
|
||||
|
||||
Example when wrapping a gtsam-based project:
|
||||
|
||||
```cpp
|
||||
// forward declarations
|
||||
virtual class gtsam::NonlinearFactor
|
||||
virtual class gtsam::NoiseModelFactor : gtsam::NonlinearFactor
|
||||
// class definition
|
||||
#include <MyFactor.h>
|
||||
virtual class MyFactor : gtsam::NoiseModelFactor {...};
|
||||
```
|
||||
|
||||
- **DO NOT** re-define an overriden function already declared in the external (forward-declared) base class
|
||||
- This will cause an ambiguity problem in Pybind header file.
|
||||
|
||||
|
||||
### TODO
|
||||
- Default values for arguments.
|
||||
- WORKAROUND: make multiple versions of the same function for different configurations of default arguments.
|
||||
- Handle `gtsam::Rot3M` conversions to quaternions.
|
||||
- Parse return of const ref arguments.
|
||||
- Parse `std::string` variants and convert directly to special string.
|
||||
- Add enum support.
|
||||
- Add generalized serialization support via `boost.serialization` with hooks to MATLAB save/load.
|
18
README.md
18
README.md
|
@ -3,12 +3,14 @@
|
|||
The wrap library wraps the GTSAM library into a Python library or MATLAB toolbox.
|
||||
It was designed to be more general than just wrapping GTSAM. For notes on creating a wrap interface, see `gtsam.h` for what features can be wrapped into a toolbox, as well as the current state of the toolbox for GTSAM.
|
||||
|
||||
## Prerequisites: Pybind11 and pyparsing
|
||||
## Prerequisites
|
||||
|
||||
`Pybind11` and `pyparsing`
|
||||
|
||||
1. This library uses `pybind11`, which is included as a subdirectory in GTSAM.
|
||||
2. The `interface_parser.py` in this library uses `pyparsing` to parse the interface file `gtsam.h`. Please install it first in your current Python environment before attempting the build.
|
||||
|
||||
```
|
||||
```sh
|
||||
python3 -m pip install pyparsing
|
||||
```
|
||||
|
||||
|
@ -42,6 +44,10 @@ pybind_wrap(${PROJECT_NAME}_py # target
|
|||
|
||||
For more information, please follow our [tutorial](https://github.com/borglab/gtsam-project-python).
|
||||
|
||||
## Documentation
|
||||
|
||||
Documentation for wrapping C++ code can be found [here](https://github.com/borglab/wrap/blob/master/DOCS.md).
|
||||
|
||||
## Python Wrapper
|
||||
|
||||
**WARNING: On macOS, you have to statically build GTSAM to use the wrapper.**
|
||||
|
@ -51,13 +57,13 @@ For more information, please follow our [tutorial](https://github.com/borglab/gt
|
|||
|
||||
1. Just run python then import GTSAM and play around:
|
||||
|
||||
```
|
||||
```python
|
||||
import gtsam
|
||||
gtsam.__dir__()
|
||||
```
|
||||
|
||||
1. Run the unittests:
|
||||
```
|
||||
```sh
|
||||
python -m unittest discover
|
||||
```
|
||||
1. Edit the unittests in `python/gtsam/*.py` and simply rerun the test.
|
||||
|
@ -66,11 +72,11 @@ For more information, please follow our [tutorial](https://github.com/borglab/gt
|
|||
|
||||
1. Do `make install` and `cd <gtsam_install_folder>/python`. Here, you can:
|
||||
1. Run the unittests:
|
||||
```
|
||||
```sh
|
||||
python setup.py test
|
||||
```
|
||||
2. Install `gtsam` to your current Python environment.
|
||||
```
|
||||
```sh
|
||||
python setup.py install
|
||||
```
|
||||
- NOTE: It's a good idea to create a virtual environment otherwise it will be installed in your system Python's site-packages.
|
||||
|
|
|
@ -6,37 +6,23 @@ All Rights Reserved
|
|||
See LICENSE for the license information
|
||||
|
||||
Parser to get the interface of a C++ source file
|
||||
Author: Duy Nguyen Ta, Fan Jiang, Matthew Sklar and Frank Dellaert
|
||||
Author: Duy Nguyen Ta, Fan Jiang, Matthew Sklar, Varun Agrawal, and Frank Dellaert
|
||||
"""
|
||||
import os
|
||||
import sys
|
||||
|
||||
from pyparsing import (
|
||||
alphas,
|
||||
alphanums,
|
||||
cppStyleComment,
|
||||
delimitedList,
|
||||
empty,
|
||||
nums,
|
||||
stringEnd,
|
||||
CharsNotIn,
|
||||
Forward,
|
||||
Group,
|
||||
Keyword,
|
||||
Literal,
|
||||
OneOrMore,
|
||||
Optional,
|
||||
Or,
|
||||
ParseException,
|
||||
ParserElement,
|
||||
Suppress,
|
||||
Word,
|
||||
ZeroOrMore,
|
||||
)
|
||||
# pylint: disable=unnecessary-lambda, unused-import, expression-not-assigned, no-else-return, protected-access, too-few-public-methods, too-many-arguments
|
||||
|
||||
import typing
|
||||
|
||||
from pyparsing import (CharsNotIn, Forward, Group, Keyword, Literal, OneOrMore,
|
||||
Optional, Or, ParseException, ParserElement, Suppress,
|
||||
Word, ZeroOrMore, alphanums, alphas, cppStyleComment,
|
||||
delimitedList, empty, nums, stringEnd)
|
||||
|
||||
ParserElement.enablePackrat()
|
||||
|
||||
# rule for identifiers (e.g. variable names)
|
||||
IDENT = Word(alphas + '_', alphanums + '_') ^ Word(nums)
|
||||
|
||||
POINTER, REF = map(Literal, "*&")
|
||||
LPAREN, RPAREN, LBRACE, RBRACE, COLON, SEMI_COLON = map(Suppress, "(){}:;")
|
||||
LOPBRACK, ROPBRACK, COMMA, EQUAL = map(Suppress, "<>,=")
|
||||
|
@ -70,9 +56,9 @@ BASIS_TYPES = map(
|
|||
)
|
||||
|
||||
|
||||
class Typename(object):
|
||||
class Typename:
|
||||
"""
|
||||
Type's name with full namespaces.
|
||||
Type's name with full namespaces, used in Type class.
|
||||
"""
|
||||
|
||||
namespaces_name_rule = delimitedList(IDENT, "::")
|
||||
|
@ -86,34 +72,38 @@ class Typename(object):
|
|||
)
|
||||
).setParseAction(lambda t: Typename(t.namespaces_name, t.instantiations))
|
||||
|
||||
def __init__(self, namespaces_name, instantiations=[]):
|
||||
def __init__(self, namespaces_name, instantiations=()):
|
||||
self.namespaces = namespaces_name[:-1]
|
||||
self.name = namespaces_name[-1]
|
||||
|
||||
if instantiations:
|
||||
if not isinstance(instantiations, list):
|
||||
if not isinstance(instantiations, typing.Iterable):
|
||||
self.instantiations = instantiations.asList()
|
||||
else:
|
||||
self.instantiations = instantiations
|
||||
else:
|
||||
self.instantiations = []
|
||||
|
||||
if self.name in ["Matrix", "Vector"] and not self.namespaces:
|
||||
self.namespaces = ["gtsam"]
|
||||
|
||||
@staticmethod
|
||||
def from_parse_result(parse_result):
|
||||
"""Return the typename from the parsed result."""
|
||||
return parse_result[0]
|
||||
|
||||
def __repr__(self):
|
||||
return self.to_cpp()
|
||||
|
||||
def instantiated_name(self):
|
||||
"""Get the instantiated name of the type."""
|
||||
res = self.name
|
||||
for instantiation in self.instantiations:
|
||||
res += instantiation.instantiated_name()
|
||||
return res
|
||||
|
||||
def to_cpp(self):
|
||||
"""Generate the C++ code for wrapping."""
|
||||
idx = 1 if self.namespaces and not self.namespaces[0] else 0
|
||||
if self.instantiations:
|
||||
cpp_name = self.name + "<{}>".format(
|
||||
|
@ -140,8 +130,11 @@ class Typename(object):
|
|||
return not res
|
||||
|
||||
|
||||
class Type(object):
|
||||
class _QualifiedType(object):
|
||||
class Type:
|
||||
"""
|
||||
The type value that is parsed, e.g. void, string, size_t.
|
||||
"""
|
||||
class _QualifiedType:
|
||||
"""
|
||||
Type with qualifiers.
|
||||
"""
|
||||
|
@ -165,7 +158,7 @@ class Type(object):
|
|||
self.is_ptr = is_ptr
|
||||
self.is_ref = is_ref
|
||||
|
||||
class _BasisType(object):
|
||||
class _BasisType:
|
||||
"""
|
||||
Basis types don't have qualifiers and only allow copy-by-value.
|
||||
"""
|
||||
|
@ -185,6 +178,7 @@ class Type(object):
|
|||
|
||||
@staticmethod
|
||||
def from_parse_result(t):
|
||||
"""Return the resulting Type from parsing the source."""
|
||||
if t.basis:
|
||||
return Type(
|
||||
typename=t.basis,
|
||||
|
@ -211,6 +205,8 @@ class Type(object):
|
|||
|
||||
def to_cpp(self, use_boost):
|
||||
"""
|
||||
Generate the C++ code for wrapping.
|
||||
|
||||
Treat all pointers as "const shared_ptr<T>&"
|
||||
Treat Matrix and Vector as "const Matrix&" and "const Vector&" resp.
|
||||
"""
|
||||
|
@ -237,7 +233,15 @@ class Type(object):
|
|||
)
|
||||
|
||||
|
||||
class Argument(object):
|
||||
class Argument:
|
||||
"""
|
||||
The type and name of a function/method argument.
|
||||
|
||||
E.g.
|
||||
```
|
||||
void sayHello(/*s is the method argument with type `const string&`*/ const string& s);
|
||||
```
|
||||
"""
|
||||
rule = (Type.rule("ctype") + IDENT("name")).setParseAction(
|
||||
lambda t: Argument(t.ctype, t.name)
|
||||
)
|
||||
|
@ -250,7 +254,10 @@ class Argument(object):
|
|||
return '{} {}'.format(self.ctype.__repr__(), self.name)
|
||||
|
||||
|
||||
class ArgumentList(object):
|
||||
class ArgumentList:
|
||||
"""
|
||||
List of Argument objects for all arguments in a function.
|
||||
"""
|
||||
rule = Optional(delimitedList(Argument.rule)("args_list")).setParseAction(
|
||||
lambda t: ArgumentList.from_parse_result(t.args_list)
|
||||
)
|
||||
|
@ -262,6 +269,7 @@ class ArgumentList(object):
|
|||
|
||||
@staticmethod
|
||||
def from_parse_result(parse_result):
|
||||
"""Return the result of parsing."""
|
||||
if parse_result:
|
||||
return ArgumentList(parse_result.asList())
|
||||
else:
|
||||
|
@ -271,13 +279,20 @@ class ArgumentList(object):
|
|||
return self.args_list.__repr__()
|
||||
|
||||
def args_names(self):
|
||||
"""Return a list of the names of all the arguments."""
|
||||
return [arg.name for arg in self.args_list]
|
||||
|
||||
def to_cpp(self, use_boost):
|
||||
"""Generate the C++ code for wrapping."""
|
||||
return [arg.ctype.to_cpp(use_boost) for arg in self.args_list]
|
||||
|
||||
|
||||
class ReturnType(object):
|
||||
class ReturnType:
|
||||
"""
|
||||
Rule to parse the return type.
|
||||
|
||||
The return type can either be a single type or a pair such as <type1, type2>.
|
||||
"""
|
||||
_pair = (
|
||||
PAIR.suppress()
|
||||
+ LOPBRACK
|
||||
|
@ -295,6 +310,9 @@ class ReturnType(object):
|
|||
self.type2 = type2
|
||||
|
||||
def is_void(self):
|
||||
"""
|
||||
Check if the return type is void.
|
||||
"""
|
||||
return self.type1.typename.name == "void" and not self.type2
|
||||
|
||||
def __repr__(self):
|
||||
|
@ -303,6 +321,7 @@ class ReturnType(object):
|
|||
)
|
||||
|
||||
def to_cpp(self):
|
||||
"""Generate the C++ code for wrapping."""
|
||||
if self.type2:
|
||||
return "std::pair<{type1},{type2}>".format(
|
||||
type1=self.type1.to_cpp(), type2=self.type2.to_cpp()
|
||||
|
@ -311,8 +330,20 @@ class ReturnType(object):
|
|||
return self.type1.to_cpp()
|
||||
|
||||
|
||||
class Template(object):
|
||||
class TypenameAndInstantiations(object):
|
||||
class Template:
|
||||
"""
|
||||
Rule to parse templated values in the interface file.
|
||||
|
||||
E.g.
|
||||
template<POSE> // this is the Template.
|
||||
class Camera { ... };
|
||||
"""
|
||||
class TypenameAndInstantiations:
|
||||
"""
|
||||
Rule to parse the template parameters.
|
||||
|
||||
template<typename POSE> // POSE is the Instantiation.
|
||||
"""
|
||||
rule = (
|
||||
IDENT("typename")
|
||||
+ Optional(
|
||||
|
@ -351,8 +382,21 @@ class Template(object):
|
|||
self.typenames = [ti.typename for ti in ti_list]
|
||||
self.instantiations = [ti.instantiations for ti in ti_list]
|
||||
|
||||
def __repr__(self):
|
||||
return "<{0}>".format(", ".join(self.typenames))
|
||||
|
||||
class Method(object):
|
||||
|
||||
class Method:
|
||||
"""
|
||||
Rule to parse a method in a class.
|
||||
|
||||
E.g.
|
||||
```
|
||||
class Hello {
|
||||
void sayHello() const;
|
||||
};
|
||||
```
|
||||
"""
|
||||
rule = (
|
||||
Optional(Template.rule("template"))
|
||||
+ ReturnType.rule("return_type")
|
||||
|
@ -387,7 +431,17 @@ class Method(object):
|
|||
)
|
||||
|
||||
|
||||
class StaticMethod(object):
|
||||
class StaticMethod:
|
||||
"""
|
||||
Rule to parse all the static methods in a class.
|
||||
|
||||
E.g.
|
||||
```
|
||||
class Hello {
|
||||
static void changeGreeting();
|
||||
};
|
||||
```
|
||||
"""
|
||||
rule = (
|
||||
STATIC
|
||||
+ ReturnType.rule("return_type")
|
||||
|
@ -411,10 +465,15 @@ class StaticMethod(object):
|
|||
return "static {} {}{}".format(self.return_type, self.name, self.args)
|
||||
|
||||
def to_cpp(self):
|
||||
"""Generate the C++ code for wrapping."""
|
||||
return self.name
|
||||
|
||||
|
||||
class Constructor(object):
|
||||
class Constructor:
|
||||
"""
|
||||
Rule to parse the class constructor.
|
||||
Can have 0 or more arguments.
|
||||
"""
|
||||
rule = (
|
||||
IDENT("name")
|
||||
+ LPAREN
|
||||
|
@ -433,7 +492,17 @@ class Constructor(object):
|
|||
return "Constructor: {}".format(self.name)
|
||||
|
||||
|
||||
class Property(object):
|
||||
class Property:
|
||||
"""
|
||||
Rule to parse the variable members of a class.
|
||||
|
||||
E.g.
|
||||
```
|
||||
class Hello {
|
||||
string name; // This is a property.
|
||||
};
|
||||
````
|
||||
"""
|
||||
rule = (Type.rule("ctype") + IDENT("name") + SEMI_COLON).setParseAction(
|
||||
lambda t: Property(t.ctype, t.name)
|
||||
)
|
||||
|
@ -441,10 +510,6 @@ class Property(object):
|
|||
def __init__(self, ctype, name, parent=''):
|
||||
self.ctype = ctype
|
||||
self.name = name
|
||||
# Check type constraints: no pointer, no ref.
|
||||
if self.ctype.is_ptr or self.ctype.is_ref:
|
||||
raise ValueError("Can't deal with pointer/ref class properties.")
|
||||
|
||||
self.parent = parent
|
||||
|
||||
def __repr__(self):
|
||||
|
@ -452,6 +517,7 @@ class Property(object):
|
|||
|
||||
|
||||
def collect_namespaces(obj):
|
||||
"""Get the chain of namespaces from the lowest to highest for the given object."""
|
||||
namespaces = []
|
||||
ancestor = obj.parent
|
||||
while ancestor and ancestor.name:
|
||||
|
@ -460,8 +526,21 @@ def collect_namespaces(obj):
|
|||
return [''] + namespaces
|
||||
|
||||
|
||||
class Class(object):
|
||||
class MethodsAndProperties(object):
|
||||
class Class:
|
||||
"""
|
||||
Rule to parse a class defined in the interface file.
|
||||
|
||||
E.g.
|
||||
```
|
||||
class Hello {
|
||||
...
|
||||
};
|
||||
```
|
||||
"""
|
||||
class MethodsAndProperties:
|
||||
"""
|
||||
Rule for all the methods and properties within a class.
|
||||
"""
|
||||
rule = ZeroOrMore(
|
||||
Constructor.rule ^ StaticMethod.rule ^ Method.rule ^ Property.rule
|
||||
).setParseAction(lambda t: Class.MethodsAndProperties(t.asList()))
|
||||
|
@ -549,10 +628,19 @@ class Class(object):
|
|||
_property.parent = self
|
||||
|
||||
def namespaces(self):
|
||||
"""Get the namespaces which this class is nested under as a list."""
|
||||
return collect_namespaces(self)
|
||||
|
||||
|
||||
class TypedefTemplateInstantiation(object):
|
||||
class TypedefTemplateInstantiation:
|
||||
"""
|
||||
Rule for parsing typedefs (with templates) within the interface file.
|
||||
|
||||
E.g.
|
||||
```
|
||||
typedef SuperComplexName<Arg1, Arg2, Arg3> EasierName;
|
||||
```
|
||||
"""
|
||||
rule = (
|
||||
TYPEDEF + Typename.rule("typename") + IDENT("new_name") + SEMI_COLON
|
||||
).setParseAction(
|
||||
|
@ -567,7 +655,10 @@ class TypedefTemplateInstantiation(object):
|
|||
self.parent = parent
|
||||
|
||||
|
||||
class Include(object):
|
||||
class Include:
|
||||
"""
|
||||
Rule to parse #include directives.
|
||||
"""
|
||||
rule = (
|
||||
INCLUDE + LOPBRACK + CharsNotIn('>')("header") + ROPBRACK
|
||||
).setParseAction(lambda t: Include(t.header))
|
||||
|
@ -580,7 +671,10 @@ class Include(object):
|
|||
return "#include <{}>".format(self.header)
|
||||
|
||||
|
||||
class ForwardDeclaration(object):
|
||||
class ForwardDeclaration:
|
||||
"""
|
||||
Rule to parse forward declarations in the interface file.
|
||||
"""
|
||||
rule = (
|
||||
Optional(VIRTUAL("is_virtual"))
|
||||
+ CLASS
|
||||
|
@ -606,7 +700,10 @@ class ForwardDeclaration(object):
|
|||
)
|
||||
|
||||
|
||||
class GlobalFunction(object):
|
||||
class GlobalFunction:
|
||||
"""
|
||||
Rule to parse functions defined in the global scope.
|
||||
"""
|
||||
rule = (
|
||||
ReturnType.rule("return_type")
|
||||
+ IDENT("name")
|
||||
|
@ -634,10 +731,18 @@ class GlobalFunction(object):
|
|||
)
|
||||
|
||||
def to_cpp(self):
|
||||
"""Generate the C++ code for wrapping."""
|
||||
return self.name
|
||||
|
||||
|
||||
def find_sub_namespace(namespace, str_namespaces):
|
||||
"""
|
||||
Get the namespaces nested under `namespace`, filtered by a list of namespace strings.
|
||||
|
||||
Args:
|
||||
namespace: The top-level namespace under which to find sub-namespaces.
|
||||
str_namespaces: The list of namespace strings to filter against.
|
||||
"""
|
||||
if not str_namespaces:
|
||||
return [namespace]
|
||||
|
||||
|
@ -659,7 +764,8 @@ def find_sub_namespace(namespace, str_namespaces):
|
|||
return res
|
||||
|
||||
|
||||
class Namespace(object):
|
||||
class Namespace:
|
||||
"""Rule for parsing a namespace in the interface file."""
|
||||
rule = Forward()
|
||||
rule << (
|
||||
NAMESPACE
|
||||
|
@ -687,6 +793,7 @@ class Namespace(object):
|
|||
|
||||
@staticmethod
|
||||
def from_parse_result(t):
|
||||
"""Return the result of parsing."""
|
||||
if t.content:
|
||||
content = t.content.asList()
|
||||
else:
|
||||
|
@ -717,6 +824,7 @@ class Namespace(object):
|
|||
return res[0]
|
||||
|
||||
def top_level(self):
|
||||
"""Return the top leve namespace."""
|
||||
if self.name == '' or self.parent == '':
|
||||
return self
|
||||
else:
|
||||
|
@ -726,15 +834,23 @@ class Namespace(object):
|
|||
return "Namespace: {}\n\t{}".format(self.name, self.content)
|
||||
|
||||
def full_namespaces(self):
|
||||
"""Get the full namespace list."""
|
||||
ancestors = collect_namespaces(self)
|
||||
if self.name:
|
||||
ancestors.append(self.name)
|
||||
return ancestors
|
||||
|
||||
|
||||
class Module(object):
|
||||
class Module:
|
||||
"""
|
||||
Module is just a global namespace.
|
||||
|
||||
E.g.
|
||||
```
|
||||
namespace gtsam {
|
||||
...
|
||||
}
|
||||
```
|
||||
"""
|
||||
|
||||
rule = (
|
||||
|
@ -752,5 +868,6 @@ class Module(object):
|
|||
rule.ignore(cppStyleComment)
|
||||
|
||||
@staticmethod
|
||||
def parseString(str):
|
||||
return Module.rule.parseString(str)[0]
|
||||
def parseString(s: str):
|
||||
"""Parse the source string and apply the rules."""
|
||||
return Module.rule.parseString(s)[0]
|
||||
|
|
|
@ -7,8 +7,11 @@ All Rights Reserved
|
|||
See LICENSE for the license information
|
||||
|
||||
Code generator for wrapping a C++ module with Pybind11
|
||||
Author: Duy Nguyen Ta, Fan Jiang, Matthew Sklar and Frank Dellaert
|
||||
Author: Duy Nguyen Ta, Fan Jiang, Matthew Sklar, Varun Agrawal, and Frank Dellaert
|
||||
"""
|
||||
|
||||
# pylint: disable=too-many-arguments, too-many-instance-attributes, no-self-use, no-else-return, too-many-arguments, unused-format-string-argument
|
||||
|
||||
import re
|
||||
import textwrap
|
||||
|
||||
|
@ -16,13 +19,16 @@ import gtwrap.interface_parser as parser
|
|||
import gtwrap.template_instantiator as instantiator
|
||||
|
||||
|
||||
class PybindWrapper(object):
|
||||
class PybindWrapper:
|
||||
"""
|
||||
Class to generate binding code for Pybind11 specifically.
|
||||
"""
|
||||
def __init__(self,
|
||||
module,
|
||||
module_name,
|
||||
top_module_namespaces='',
|
||||
use_boost=False,
|
||||
ignore_classes=[],
|
||||
ignore_classes=(),
|
||||
module_template=""):
|
||||
self.module = module
|
||||
self.module_name = module_name
|
||||
|
@ -34,6 +40,7 @@ class PybindWrapper(object):
|
|||
self.python_keywords = ['print', 'lambda']
|
||||
|
||||
def _py_args_names(self, args_list):
|
||||
"""Set the argument names in Pybind11 format."""
|
||||
names = args_list.args_names()
|
||||
if names:
|
||||
py_args = ['py::arg("{}")'.format(name) for name in names]
|
||||
|
@ -42,6 +49,7 @@ class PybindWrapper(object):
|
|||
return ''
|
||||
|
||||
def _method_args_signature_with_names(self, args_list):
|
||||
"""Define the method signature types with the argument names."""
|
||||
cpp_types = args_list.to_cpp(self.use_boost)
|
||||
names = args_list.args_names()
|
||||
types_names = ["{} {}".format(ctype, name) for ctype, name in zip(cpp_types, names)]
|
||||
|
@ -49,6 +57,7 @@ class PybindWrapper(object):
|
|||
return ','.join(types_names)
|
||||
|
||||
def wrap_ctors(self, my_class):
|
||||
"""Wrap the constructors."""
|
||||
res = ""
|
||||
for ctor in my_class.ctors:
|
||||
res += ('\n' + ' ' * 8 + '.def(py::init<{args_cpp_types}>()'
|
||||
|
@ -115,8 +124,10 @@ class PybindWrapper(object):
|
|||
'{py_args_names}){suffix}'.format(
|
||||
prefix=prefix,
|
||||
cdef="def_static" if is_static else "def",
|
||||
py_method=py_method if not py_method in self.python_keywords else py_method + "_",
|
||||
opt_self="{cpp_class}* self".format(cpp_class=cpp_class) if is_method else "",
|
||||
py_method=py_method if not py_method in self.python_keywords
|
||||
else py_method + "_",
|
||||
opt_self="{cpp_class}* self".format(
|
||||
cpp_class=cpp_class) if is_method else "",
|
||||
cpp_class=cpp_class,
|
||||
cpp_method=cpp_method,
|
||||
opt_comma=',' if is_method and args_names else '',
|
||||
|
@ -152,6 +163,7 @@ class PybindWrapper(object):
|
|||
return ret
|
||||
|
||||
def wrap_methods(self, methods, cpp_class, prefix='\n' + ' ' * 8, suffix=''):
|
||||
"""Wrap all the methods in the `cpp_class`."""
|
||||
res = ""
|
||||
for method in methods:
|
||||
|
||||
|
@ -176,6 +188,7 @@ class PybindWrapper(object):
|
|||
return res
|
||||
|
||||
def wrap_properties(self, properties, cpp_class, prefix='\n' + ' ' * 8):
|
||||
"""Wrap all the properties in the `cpp_class`."""
|
||||
res = ""
|
||||
for prop in properties:
|
||||
res += ('{prefix}.def_{property}("{property_name}", '
|
||||
|
@ -188,50 +201,61 @@ class PybindWrapper(object):
|
|||
return res
|
||||
|
||||
def wrap_instantiated_class(self, instantiated_class):
|
||||
"""Wrap the class."""
|
||||
module_var = self._gen_module_var(instantiated_class.namespaces())
|
||||
cpp_class = instantiated_class.cpp_class()
|
||||
if cpp_class in self.ignore_classes:
|
||||
return ""
|
||||
return ('\n py::class_<{cpp_class}, {class_parent}'
|
||||
'{shared_ptr_type}::shared_ptr<{cpp_class}>>({module_var}, "{class_name}")'
|
||||
'{wrapped_ctors}'
|
||||
'{wrapped_methods}'
|
||||
'{wrapped_static_methods}'
|
||||
'{wrapped_properties};\n'.format(
|
||||
shared_ptr_type=('boost' if self.use_boost else 'std'),
|
||||
cpp_class=cpp_class,
|
||||
class_name=instantiated_class.name,
|
||||
class_parent=str(instantiated_class.parent_class) +
|
||||
(', ' if instantiated_class.parent_class else ''),
|
||||
module_var=module_var,
|
||||
wrapped_ctors=self.wrap_ctors(instantiated_class),
|
||||
wrapped_methods=self.wrap_methods(instantiated_class.methods, cpp_class),
|
||||
wrapped_static_methods=self.wrap_methods(instantiated_class.static_methods, cpp_class),
|
||||
wrapped_properties=self.wrap_properties(instantiated_class.properties, cpp_class),
|
||||
))
|
||||
return (
|
||||
'\n py::class_<{cpp_class}, {class_parent}'
|
||||
'{shared_ptr_type}::shared_ptr<{cpp_class}>>({module_var}, "{class_name}")'
|
||||
'{wrapped_ctors}'
|
||||
'{wrapped_methods}'
|
||||
'{wrapped_static_methods}'
|
||||
'{wrapped_properties};\n'.format(
|
||||
shared_ptr_type=('boost' if self.use_boost else 'std'),
|
||||
cpp_class=cpp_class,
|
||||
class_name=instantiated_class.name,
|
||||
class_parent=str(instantiated_class.parent_class) +
|
||||
(', ' if instantiated_class.parent_class else ''),
|
||||
module_var=module_var,
|
||||
wrapped_ctors=self.wrap_ctors(instantiated_class),
|
||||
wrapped_methods=self.wrap_methods(instantiated_class.methods,
|
||||
cpp_class),
|
||||
wrapped_static_methods=self.wrap_methods(
|
||||
instantiated_class.static_methods, cpp_class),
|
||||
wrapped_properties=self.wrap_properties(
|
||||
instantiated_class.properties, cpp_class),
|
||||
))
|
||||
|
||||
def wrap_stl_class(self, stl_class):
|
||||
"""Wrap STL containers."""
|
||||
module_var = self._gen_module_var(stl_class.namespaces())
|
||||
cpp_class = stl_class.cpp_class()
|
||||
if cpp_class in self.ignore_classes:
|
||||
return ""
|
||||
|
||||
return ('\n py::class_<{cpp_class}, {class_parent}'
|
||||
'{shared_ptr_type}::shared_ptr<{cpp_class}>>({module_var}, "{class_name}")'
|
||||
'{wrapped_ctors}'
|
||||
'{wrapped_methods}'
|
||||
'{wrapped_static_methods}'
|
||||
'{wrapped_properties};\n'.format(
|
||||
shared_ptr_type=('boost' if self.use_boost else 'std'),
|
||||
cpp_class=cpp_class,
|
||||
class_name=stl_class.name,
|
||||
class_parent=str(stl_class.parent_class) + (', ' if stl_class.parent_class else ''),
|
||||
module_var=module_var,
|
||||
wrapped_ctors=self.wrap_ctors(stl_class),
|
||||
wrapped_methods=self.wrap_methods(stl_class.methods, cpp_class),
|
||||
wrapped_static_methods=self.wrap_methods(stl_class.static_methods, cpp_class),
|
||||
wrapped_properties=self.wrap_properties(stl_class.properties, cpp_class),
|
||||
))
|
||||
return (
|
||||
'\n py::class_<{cpp_class}, {class_parent}'
|
||||
'{shared_ptr_type}::shared_ptr<{cpp_class}>>({module_var}, "{class_name}")'
|
||||
'{wrapped_ctors}'
|
||||
'{wrapped_methods}'
|
||||
'{wrapped_static_methods}'
|
||||
'{wrapped_properties};\n'.format(
|
||||
shared_ptr_type=('boost' if self.use_boost else 'std'),
|
||||
cpp_class=cpp_class,
|
||||
class_name=stl_class.name,
|
||||
class_parent=str(stl_class.parent_class) +
|
||||
(', ' if stl_class.parent_class else ''),
|
||||
module_var=module_var,
|
||||
wrapped_ctors=self.wrap_ctors(stl_class),
|
||||
wrapped_methods=self.wrap_methods(stl_class.methods,
|
||||
cpp_class),
|
||||
wrapped_static_methods=self.wrap_methods(
|
||||
stl_class.static_methods, cpp_class),
|
||||
wrapped_properties=self.wrap_properties(
|
||||
stl_class.properties, cpp_class),
|
||||
))
|
||||
|
||||
def _partial_match(self, namespaces1, namespaces2):
|
||||
for i in range(min(len(namespaces1), len(namespaces2))):
|
||||
|
@ -252,6 +276,7 @@ class PybindWrapper(object):
|
|||
return name
|
||||
|
||||
def wrap_namespace(self, namespace):
|
||||
"""Wrap the complete `namespace`."""
|
||||
wrapped = ""
|
||||
includes = ""
|
||||
|
||||
|
@ -298,7 +323,10 @@ class PybindWrapper(object):
|
|||
wrapped += self.wrap_instantiated_class(element)
|
||||
|
||||
# Global functions.
|
||||
all_funcs = [func for func in namespace.content if isinstance(func, parser.GlobalFunction)]
|
||||
all_funcs = [
|
||||
func for func in namespace.content
|
||||
if isinstance(func, parser.GlobalFunction)
|
||||
]
|
||||
wrapped += self.wrap_methods(
|
||||
all_funcs,
|
||||
self._add_namespaces('', namespaces)[:-2],
|
||||
|
@ -308,6 +336,7 @@ class PybindWrapper(object):
|
|||
return wrapped, includes
|
||||
|
||||
def wrap(self):
|
||||
"""Wrap the code in the interface file."""
|
||||
wrapped_namespace, includes = self.wrap_namespace(self.module)
|
||||
|
||||
# Export classes for serialization.
|
||||
|
@ -323,14 +352,16 @@ class PybindWrapper(object):
|
|||
)
|
||||
boost_class_export += "BOOST_CLASS_EXPORT({new_name})\n".format(new_name=new_name, )
|
||||
|
||||
holder_type = "PYBIND11_DECLARE_HOLDER_TYPE(TYPE_PLACEHOLDER_DONOTUSE, " \
|
||||
"{shared_ptr_type}::shared_ptr<TYPE_PLACEHOLDER_DONOTUSE>);"
|
||||
include_boost = "#include <boost/shared_ptr.hpp>" if self.use_boost else ""
|
||||
|
||||
return self.module_template.format(
|
||||
include_boost="#include <boost/shared_ptr.hpp>" if self.use_boost else "",
|
||||
include_boost=include_boost,
|
||||
module_name=self.module_name,
|
||||
includes=includes,
|
||||
hoder_type=
|
||||
"PYBIND11_DECLARE_HOLDER_TYPE(TYPE_PLACEHOLDER_DONOTUSE, {shared_ptr_type}::shared_ptr<TYPE_PLACEHOLDER_DONOTUSE>);"
|
||||
.format(shared_ptr_type=('boost' if self.use_boost else 'std')) if self.use_boost else "",
|
||||
holder_type=holder_type.format(shared_ptr_type=('boost' if self.use_boost else 'std'))
|
||||
if self.use_boost else "",
|
||||
wrapped_namespace=wrapped_namespace,
|
||||
boost_class_export=boost_class_export,
|
||||
)
|
||||
|
||||
|
|
|
@ -1,15 +1,45 @@
|
|||
"""Code to help instantiate templated classes, methods and functions."""
|
||||
|
||||
# pylint: disable=too-many-arguments, too-many-instance-attributes, no-self-use, no-else-return, too-many-arguments, unused-format-string-argument, unused-variable
|
||||
|
||||
import itertools
|
||||
from copy import deepcopy
|
||||
from typing import List
|
||||
|
||||
import gtwrap.interface_parser as parser
|
||||
|
||||
|
||||
def instantiate_type(ctype, template_typenames, instantiations, cpp_typename, instantiated_class=None):
|
||||
def instantiate_type(ctype: parser.Type,
|
||||
template_typenames: List[str],
|
||||
instantiations: List[parser.Typename],
|
||||
cpp_typename: parser.Typename,
|
||||
instantiated_class=None):
|
||||
"""
|
||||
Instantiate template typename for @p ctype.
|
||||
|
||||
Args:
|
||||
instiated_class (InstantiatedClass):
|
||||
|
||||
@return If ctype's name is in the @p template_typenames, return the
|
||||
corresponding type to replace in @p instantiations.
|
||||
If ctype name is `This`, return the new typename @p `cpp_typename`.
|
||||
Otherwise, return the original ctype.
|
||||
"""
|
||||
# make a deep copy so that there is no overwriting of original template params
|
||||
ctype = deepcopy(ctype)
|
||||
|
||||
# Check if the return type has template parameters
|
||||
if len(ctype.typename.instantiations) > 0:
|
||||
for idx, instantiation in enumerate(ctype.typename.instantiations):
|
||||
if instantiation.name in template_typenames:
|
||||
template_idx = template_typenames.index(instantiation.name)
|
||||
ctype.typename.instantiations[idx] = instantiations[
|
||||
template_idx]
|
||||
|
||||
return ctype
|
||||
|
||||
str_arg_typename = str(ctype.typename)
|
||||
|
||||
if str_arg_typename in template_typenames:
|
||||
idx = template_typenames.index(str_arg_typename)
|
||||
return parser.Type(
|
||||
|
@ -20,7 +50,6 @@ def instantiate_type(ctype, template_typenames, instantiations, cpp_typename, in
|
|||
is_basis=ctype.is_basis,
|
||||
)
|
||||
elif str_arg_typename == 'This':
|
||||
# import sys
|
||||
if instantiated_class:
|
||||
name = instantiated_class.original.name
|
||||
namespaces_name = instantiated_class.namespaces()
|
||||
|
@ -29,8 +58,8 @@ def instantiate_type(ctype, template_typenames, instantiations, cpp_typename, in
|
|||
# ctype, instantiations, cpp_typename, instantiated_class.instantiations
|
||||
# ), file=sys.stderr)
|
||||
cpp_typename = parser.Typename(
|
||||
namespaces_name, instantiations=[inst for inst in instantiated_class.instantiations]
|
||||
)
|
||||
namespaces_name,
|
||||
instantiations=instantiated_class.instantiations)
|
||||
return parser.Type(
|
||||
typename=cpp_typename,
|
||||
is_const=ctype.is_const,
|
||||
|
@ -70,12 +99,18 @@ def instantiate_args_list(args_list, template_typenames, instantiations,
|
|||
|
||||
def instantiate_return_type(return_type, template_typenames, instantiations,
|
||||
cpp_typename, instantiated_class=None):
|
||||
new_type1 = instantiate_type(
|
||||
return_type.type1, template_typenames, instantiations, cpp_typename, instantiated_class=instantiated_class)
|
||||
"""Instantiate the return type."""
|
||||
new_type1 = instantiate_type(return_type.type1,
|
||||
template_typenames,
|
||||
instantiations,
|
||||
cpp_typename,
|
||||
instantiated_class=instantiated_class)
|
||||
if return_type.type2:
|
||||
new_type2 = instantiate_type(
|
||||
return_type.type2, template_typenames, instantiations,
|
||||
cpp_typename, instantiated_class=instantiated_class)
|
||||
new_type2 = instantiate_type(return_type.type2,
|
||||
template_typenames,
|
||||
instantiations,
|
||||
cpp_typename,
|
||||
instantiated_class=instantiated_class)
|
||||
else:
|
||||
new_type2 = ''
|
||||
return parser.ReturnType(new_type1, new_type2)
|
||||
|
@ -91,7 +126,7 @@ def instantiate_name(original_name, instantiations):
|
|||
inst_name = ''
|
||||
|
||||
return "{}{}".format(original_name, "".join(
|
||||
[inst.instantiated_name() for inst in instantiations]))
|
||||
[inst.instantiated_name().capitalize().replace('_', '') for inst in instantiations]))
|
||||
|
||||
|
||||
class InstantiatedMethod(parser.Method):
|
||||
|
@ -111,6 +146,7 @@ class InstantiatedMethod(parser.Method):
|
|||
self.return_type = original.return_type
|
||||
self.args = original.args
|
||||
else:
|
||||
#TODO(Varun) enable multiple templates for methods
|
||||
if len(self.original.template.typenames) > 1:
|
||||
raise ValueError("Can only instantiate template method with "
|
||||
"single template parameter.")
|
||||
|
@ -133,11 +169,20 @@ class InstantiatedMethod(parser.Method):
|
|||
)
|
||||
self.args = parser.ArgumentList(instantiated_args)
|
||||
|
||||
super().__init__(self.template,
|
||||
self.name,
|
||||
self.return_type,
|
||||
self.args,
|
||||
self.is_const,
|
||||
parent=self.parent)
|
||||
|
||||
def to_cpp(self):
|
||||
"""Generate the C++ code for wrapping."""
|
||||
if self.original.template:
|
||||
return "{}<{}>".format(self.original.name, self.instantiation)
|
||||
ret = "{}<{}>".format(self.original.name, self.instantiation)
|
||||
else:
|
||||
return self.original.name
|
||||
ret = self.original.name
|
||||
return ret
|
||||
|
||||
def __repr__(self):
|
||||
return "Instantiated {}".format(
|
||||
|
@ -146,7 +191,10 @@ class InstantiatedMethod(parser.Method):
|
|||
|
||||
|
||||
class InstantiatedClass(parser.Class):
|
||||
def __init__(self, original, instantiations=[], new_name=''):
|
||||
"""
|
||||
Instantiate the class defined in the interface file.
|
||||
"""
|
||||
def __init__(self, original, instantiations=(), new_name=''):
|
||||
"""
|
||||
Template <T, U>
|
||||
Instantiations: [T1, U1]
|
||||
|
@ -190,6 +238,18 @@ class InstantiatedClass(parser.Class):
|
|||
for inst in method.template.instantiations[0]:
|
||||
self.methods.append(InstantiatedMethod(method, inst))
|
||||
|
||||
super().__init__(
|
||||
self.template,
|
||||
self.is_virtual,
|
||||
self.name,
|
||||
[self.parent_class],
|
||||
self.ctors,
|
||||
self.methods,
|
||||
self.static_methods,
|
||||
self.properties,
|
||||
parent=self.parent,
|
||||
)
|
||||
|
||||
def __repr__(self):
|
||||
return "{virtual} class {name} [{cpp_class}]: {parent_class}\n"\
|
||||
"{ctors}\n{static_methods}\n{methods}".format(
|
||||
|
@ -204,6 +264,7 @@ class InstantiatedClass(parser.Class):
|
|||
)
|
||||
|
||||
def instantiate_ctors(self):
|
||||
"""Instantiate the class constructors."""
|
||||
instantiated_ctors = []
|
||||
for ctor in self.original.ctors:
|
||||
instantiated_args = instantiate_args_list(
|
||||
|
@ -220,6 +281,7 @@ class InstantiatedClass(parser.Class):
|
|||
return instantiated_ctors
|
||||
|
||||
def instantiate_static_methods(self):
|
||||
"""Instantiate static methods in the class."""
|
||||
instantiated_static_methods = []
|
||||
for static_method in self.original.static_methods:
|
||||
instantiated_args = instantiate_args_list(
|
||||
|
@ -274,6 +336,7 @@ class InstantiatedClass(parser.Class):
|
|||
return class_instantiated_methods
|
||||
|
||||
def instantiate_properties(self):
|
||||
"""Instantiate the class properties."""
|
||||
instantiated_properties = instantiate_args_list(
|
||||
self.original.properties,
|
||||
self.original.template.typenames,
|
||||
|
@ -283,6 +346,7 @@ class InstantiatedClass(parser.Class):
|
|||
return instantiated_properties
|
||||
|
||||
def cpp_class(self):
|
||||
"""Generate the C++ code for wrapping."""
|
||||
return self.cpp_typename().to_cpp()
|
||||
|
||||
def cpp_typename(self):
|
||||
|
@ -303,7 +367,10 @@ class InstantiatedClass(parser.Class):
|
|||
|
||||
def instantiate_namespace_inplace(namespace):
|
||||
"""
|
||||
@param[in/out] namespace The namespace which content will be replaced with
|
||||
Instantiate the classes and other elements in the `namespace` content and
|
||||
assign it back to the namespace content attribute.
|
||||
|
||||
@param[in/out] namespace The namespace whose content will be replaced with
|
||||
the instantiated content.
|
||||
"""
|
||||
instantiated_content = []
|
||||
|
@ -316,15 +383,14 @@ def instantiate_namespace_inplace(namespace):
|
|||
instantiated_content.append(
|
||||
InstantiatedClass(original_class, []))
|
||||
else:
|
||||
if (len(original_class.template.typenames) > 1
|
||||
and original_class.template.instantiations[0]):
|
||||
raise ValueError(
|
||||
"Can't instantiate multi-parameter templates here. "
|
||||
"Please use typedef template instantiation."
|
||||
)
|
||||
for inst in original_class.template.instantiations[0]:
|
||||
# Use itertools to get all possible combinations of instantiations
|
||||
# Works even if one template does not have an instantiation list
|
||||
for instantiations in itertools.product(
|
||||
*original_class.template.instantiations):
|
||||
instantiated_content.append(
|
||||
InstantiatedClass(original_class, [inst]))
|
||||
InstantiatedClass(original_class,
|
||||
list(instantiations)))
|
||||
|
||||
elif isinstance(element, parser.TypedefTemplateInstantiation):
|
||||
typedef_inst = element
|
||||
original_class = namespace.top_level().find_class(
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
|
||||
{boost_class_export}
|
||||
|
||||
{hoder_type}
|
||||
{holder_type}
|
||||
|
||||
#include "python/preamble.h"
|
||||
|
||||
|
|
|
@ -6,6 +6,8 @@ This script is installed via CMake to the user's binary directory
|
|||
and invoked during the wrapping by CMake.
|
||||
"""
|
||||
|
||||
# pylint: disable=import-error
|
||||
|
||||
import argparse
|
||||
|
||||
import gtwrap.interface_parser as parser
|
||||
|
@ -68,13 +70,16 @@ def main():
|
|||
if top_module_namespaces[0]:
|
||||
top_module_namespaces = [''] + top_module_namespaces
|
||||
|
||||
# Read in the complete interface (.i) file
|
||||
with open(args.src, "r") as f:
|
||||
content = f.read()
|
||||
|
||||
module = parser.Module.parseString(content)
|
||||
instantiator.instantiate_namespace_inplace(module)
|
||||
|
||||
with open(args.template, "r") as f:
|
||||
template_content = f.read()
|
||||
|
||||
wrapper = PybindWrapper(
|
||||
module=module,
|
||||
module_name=args.module_name,
|
||||
|
@ -84,7 +89,10 @@ def main():
|
|||
module_template=template_content,
|
||||
)
|
||||
|
||||
# Wrap the code and get back the cpp/cc code.
|
||||
cc_content = wrapper.wrap()
|
||||
|
||||
# Generate the C++ code which Pybind11 will use.
|
||||
with open(args.out, "w") as f:
|
||||
f.write(cc_content)
|
||||
|
||||
|
|
|
@ -0,0 +1,31 @@
|
|||
%class MultipleTemplatesIntDouble, see Doxygen page for details
|
||||
%at https://gtsam.org/doxygen/
|
||||
%
|
||||
classdef MultipleTemplatesIntDouble < handle
|
||||
properties
|
||||
ptr_MultipleTemplatesIntDouble = 0
|
||||
end
|
||||
methods
|
||||
function obj = MultipleTemplatesIntDouble(varargin)
|
||||
if nargin == 2 && isa(varargin{1}, 'uint64') && varargin{1} == uint64(5139824614673773682)
|
||||
my_ptr = varargin{2};
|
||||
geometry_wrapper(89, my_ptr);
|
||||
else
|
||||
error('Arguments do not match any overload of MultipleTemplatesIntDouble constructor');
|
||||
end
|
||||
obj.ptr_MultipleTemplatesIntDouble = my_ptr;
|
||||
end
|
||||
|
||||
function delete(obj)
|
||||
geometry_wrapper(90, obj.ptr_MultipleTemplatesIntDouble);
|
||||
end
|
||||
|
||||
function display(obj), obj.print(''); end
|
||||
%DISPLAY Calls print on the object
|
||||
function disp(obj), obj.display; end
|
||||
%DISP Calls print on the object
|
||||
end
|
||||
|
||||
methods(Static = true)
|
||||
end
|
||||
end
|
|
@ -0,0 +1,31 @@
|
|||
%class MultipleTemplatesIntFloat, see Doxygen page for details
|
||||
%at https://gtsam.org/doxygen/
|
||||
%
|
||||
classdef MultipleTemplatesIntFloat < handle
|
||||
properties
|
||||
ptr_MultipleTemplatesIntFloat = 0
|
||||
end
|
||||
methods
|
||||
function obj = MultipleTemplatesIntFloat(varargin)
|
||||
if nargin == 2 && isa(varargin{1}, 'uint64') && varargin{1} == uint64(5139824614673773682)
|
||||
my_ptr = varargin{2};
|
||||
geometry_wrapper(91, my_ptr);
|
||||
else
|
||||
error('Arguments do not match any overload of MultipleTemplatesIntFloat constructor');
|
||||
end
|
||||
obj.ptr_MultipleTemplatesIntFloat = my_ptr;
|
||||
end
|
||||
|
||||
function delete(obj)
|
||||
geometry_wrapper(92, obj.ptr_MultipleTemplatesIntFloat);
|
||||
end
|
||||
|
||||
function display(obj), obj.print(''); end
|
||||
%DISPLAY Calls print on the object
|
||||
function disp(obj), obj.display; end
|
||||
%DISP Calls print on the object
|
||||
end
|
||||
|
||||
methods(Static = true)
|
||||
end
|
||||
end
|
|
@ -12,9 +12,9 @@ classdef MyFactorPosePoint2 < handle
|
|||
function obj = MyFactorPosePoint2(varargin)
|
||||
if nargin == 2 && isa(varargin{1}, 'uint64') && varargin{1} == uint64(5139824614673773682)
|
||||
my_ptr = varargin{2};
|
||||
geometry_wrapper(89, my_ptr);
|
||||
geometry_wrapper(93, my_ptr);
|
||||
elseif nargin == 4 && isa(varargin{1},'numeric') && isa(varargin{2},'numeric') && isa(varargin{3},'double') && isa(varargin{4},'gtsam.noiseModel.Base')
|
||||
my_ptr = geometry_wrapper(90, varargin{1}, varargin{2}, varargin{3}, varargin{4});
|
||||
my_ptr = geometry_wrapper(94, varargin{1}, varargin{2}, varargin{3}, varargin{4});
|
||||
else
|
||||
error('Arguments do not match any overload of MyFactorPosePoint2 constructor');
|
||||
end
|
||||
|
@ -22,7 +22,7 @@ classdef MyFactorPosePoint2 < handle
|
|||
end
|
||||
|
||||
function delete(obj)
|
||||
geometry_wrapper(91, obj.ptr_MyFactorPosePoint2);
|
||||
geometry_wrapper(95, obj.ptr_MyFactorPosePoint2);
|
||||
end
|
||||
|
||||
function display(obj), obj.print(''); end
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
function varargout = aGlobalFunction(varargin)
|
||||
if length(varargin) == 0
|
||||
varargout{1} = geometry_wrapper(95, varargin{:});
|
||||
varargout{1} = geometry_wrapper(99, varargin{:});
|
||||
else
|
||||
error('Arguments do not match any overload of function aGlobalFunction');
|
||||
end
|
||||
|
|
|
@ -11,9 +11,11 @@
|
|||
|
||||
typedef MyTemplate<gtsam::Point2> MyTemplatePoint2;
|
||||
typedef MyTemplate<gtsam::Matrix> MyTemplateMatrix;
|
||||
typedef PrimitiveRef<double> PrimitiveRefdouble;
|
||||
typedef PrimitiveRef<double> PrimitiveRefDouble;
|
||||
typedef MyVector<3> MyVector3;
|
||||
typedef MyVector<12> MyVector12;
|
||||
typedef MultipleTemplates<int, double> MultipleTemplatesIntDouble;
|
||||
typedef MultipleTemplates<int, float> MultipleTemplatesIntFloat;
|
||||
typedef MyFactor<gtsam::Pose2, gtsam::Matrix> MyFactorPosePoint2;
|
||||
|
||||
BOOST_CLASS_EXPORT_GUID(gtsam::Point2, "gtsamPoint2");
|
||||
|
@ -31,12 +33,16 @@ typedef std::set<boost::shared_ptr<MyTemplatePoint2>*> Collector_MyTemplatePoint
|
|||
static Collector_MyTemplatePoint2 collector_MyTemplatePoint2;
|
||||
typedef std::set<boost::shared_ptr<MyTemplateMatrix>*> Collector_MyTemplateMatrix;
|
||||
static Collector_MyTemplateMatrix collector_MyTemplateMatrix;
|
||||
typedef std::set<boost::shared_ptr<PrimitiveRefdouble>*> Collector_PrimitiveRefdouble;
|
||||
static Collector_PrimitiveRefdouble collector_PrimitiveRefdouble;
|
||||
typedef std::set<boost::shared_ptr<PrimitiveRefDouble>*> Collector_PrimitiveRefDouble;
|
||||
static Collector_PrimitiveRefDouble collector_PrimitiveRefDouble;
|
||||
typedef std::set<boost::shared_ptr<MyVector3>*> Collector_MyVector3;
|
||||
static Collector_MyVector3 collector_MyVector3;
|
||||
typedef std::set<boost::shared_ptr<MyVector12>*> Collector_MyVector12;
|
||||
static Collector_MyVector12 collector_MyVector12;
|
||||
typedef std::set<boost::shared_ptr<MultipleTemplatesIntDouble>*> Collector_MultipleTemplatesIntDouble;
|
||||
static Collector_MultipleTemplatesIntDouble collector_MultipleTemplatesIntDouble;
|
||||
typedef std::set<boost::shared_ptr<MultipleTemplatesIntFloat>*> Collector_MultipleTemplatesIntFloat;
|
||||
static Collector_MultipleTemplatesIntFloat collector_MultipleTemplatesIntFloat;
|
||||
typedef std::set<boost::shared_ptr<MyFactorPosePoint2>*> Collector_MyFactorPosePoint2;
|
||||
static Collector_MyFactorPosePoint2 collector_MyFactorPosePoint2;
|
||||
|
||||
|
@ -82,10 +88,10 @@ void _deleteAllObjects()
|
|||
collector_MyTemplateMatrix.erase(iter++);
|
||||
anyDeleted = true;
|
||||
} }
|
||||
{ for(Collector_PrimitiveRefdouble::iterator iter = collector_PrimitiveRefdouble.begin();
|
||||
iter != collector_PrimitiveRefdouble.end(); ) {
|
||||
{ for(Collector_PrimitiveRefDouble::iterator iter = collector_PrimitiveRefDouble.begin();
|
||||
iter != collector_PrimitiveRefDouble.end(); ) {
|
||||
delete *iter;
|
||||
collector_PrimitiveRefdouble.erase(iter++);
|
||||
collector_PrimitiveRefDouble.erase(iter++);
|
||||
anyDeleted = true;
|
||||
} }
|
||||
{ for(Collector_MyVector3::iterator iter = collector_MyVector3.begin();
|
||||
|
@ -100,6 +106,18 @@ void _deleteAllObjects()
|
|||
collector_MyVector12.erase(iter++);
|
||||
anyDeleted = true;
|
||||
} }
|
||||
{ for(Collector_MultipleTemplatesIntDouble::iterator iter = collector_MultipleTemplatesIntDouble.begin();
|
||||
iter != collector_MultipleTemplatesIntDouble.end(); ) {
|
||||
delete *iter;
|
||||
collector_MultipleTemplatesIntDouble.erase(iter++);
|
||||
anyDeleted = true;
|
||||
} }
|
||||
{ for(Collector_MultipleTemplatesIntFloat::iterator iter = collector_MultipleTemplatesIntFloat.begin();
|
||||
iter != collector_MultipleTemplatesIntFloat.end(); ) {
|
||||
delete *iter;
|
||||
collector_MultipleTemplatesIntFloat.erase(iter++);
|
||||
anyDeleted = true;
|
||||
} }
|
||||
{ for(Collector_MyFactorPosePoint2::iterator iter = collector_MyFactorPosePoint2.begin();
|
||||
iter != collector_MyFactorPosePoint2.end(); ) {
|
||||
delete *iter;
|
||||
|
@ -912,42 +930,42 @@ void MyTemplateMatrix_Level_78(int nargout, mxArray *out[], int nargin, const mx
|
|||
out[0] = wrap_shared_ptr(boost::make_shared<MyTemplate<Matrix>>(MyTemplate<gtsam::Matrix>::Level(K)),"MyTemplateMatrix", false);
|
||||
}
|
||||
|
||||
void PrimitiveRefdouble_collectorInsertAndMakeBase_79(int nargout, mxArray *out[], int nargin, const mxArray *in[])
|
||||
void PrimitiveRefDouble_collectorInsertAndMakeBase_79(int nargout, mxArray *out[], int nargin, const mxArray *in[])
|
||||
{
|
||||
mexAtExit(&_deleteAllObjects);
|
||||
typedef boost::shared_ptr<PrimitiveRef<double>> Shared;
|
||||
|
||||
Shared *self = *reinterpret_cast<Shared**> (mxGetData(in[0]));
|
||||
collector_PrimitiveRefdouble.insert(self);
|
||||
collector_PrimitiveRefDouble.insert(self);
|
||||
}
|
||||
|
||||
void PrimitiveRefdouble_constructor_80(int nargout, mxArray *out[], int nargin, const mxArray *in[])
|
||||
void PrimitiveRefDouble_constructor_80(int nargout, mxArray *out[], int nargin, const mxArray *in[])
|
||||
{
|
||||
mexAtExit(&_deleteAllObjects);
|
||||
typedef boost::shared_ptr<PrimitiveRef<double>> Shared;
|
||||
|
||||
Shared *self = new Shared(new PrimitiveRef<double>());
|
||||
collector_PrimitiveRefdouble.insert(self);
|
||||
collector_PrimitiveRefDouble.insert(self);
|
||||
out[0] = mxCreateNumericMatrix(1, 1, mxUINT32OR64_CLASS, mxREAL);
|
||||
*reinterpret_cast<Shared**> (mxGetData(out[0])) = self;
|
||||
}
|
||||
|
||||
void PrimitiveRefdouble_deconstructor_81(int nargout, mxArray *out[], int nargin, const mxArray *in[])
|
||||
void PrimitiveRefDouble_deconstructor_81(int nargout, mxArray *out[], int nargin, const mxArray *in[])
|
||||
{
|
||||
typedef boost::shared_ptr<PrimitiveRef<double>> Shared;
|
||||
checkArguments("delete_PrimitiveRefdouble",nargout,nargin,1);
|
||||
checkArguments("delete_PrimitiveRefDouble",nargout,nargin,1);
|
||||
Shared *self = *reinterpret_cast<Shared**>(mxGetData(in[0]));
|
||||
Collector_PrimitiveRefdouble::iterator item;
|
||||
item = collector_PrimitiveRefdouble.find(self);
|
||||
if(item != collector_PrimitiveRefdouble.end()) {
|
||||
Collector_PrimitiveRefDouble::iterator item;
|
||||
item = collector_PrimitiveRefDouble.find(self);
|
||||
if(item != collector_PrimitiveRefDouble.end()) {
|
||||
delete self;
|
||||
collector_PrimitiveRefdouble.erase(item);
|
||||
collector_PrimitiveRefDouble.erase(item);
|
||||
}
|
||||
}
|
||||
|
||||
void PrimitiveRefdouble_Brutal_82(int nargout, mxArray *out[], int nargin, const mxArray *in[])
|
||||
void PrimitiveRefDouble_Brutal_82(int nargout, mxArray *out[], int nargin, const mxArray *in[])
|
||||
{
|
||||
checkArguments("PrimitiveRefdouble.Brutal",nargout,nargin,1);
|
||||
checkArguments("PrimitiveRefDouble.Brutal",nargout,nargin,1);
|
||||
double t = unwrap< double >(in[0]);
|
||||
out[0] = wrap_shared_ptr(boost::make_shared<PrimitiveRef<double>>(PrimitiveRef<double>::Brutal(t)),"PrimitiveRefdouble", false);
|
||||
}
|
||||
|
@ -1018,7 +1036,51 @@ void MyVector12_deconstructor_88(int nargout, mxArray *out[], int nargin, const
|
|||
}
|
||||
}
|
||||
|
||||
void MyFactorPosePoint2_collectorInsertAndMakeBase_89(int nargout, mxArray *out[], int nargin, const mxArray *in[])
|
||||
void MultipleTemplatesIntDouble_collectorInsertAndMakeBase_89(int nargout, mxArray *out[], int nargin, const mxArray *in[])
|
||||
{
|
||||
mexAtExit(&_deleteAllObjects);
|
||||
typedef boost::shared_ptr<MultipleTemplates<int, double>> Shared;
|
||||
|
||||
Shared *self = *reinterpret_cast<Shared**> (mxGetData(in[0]));
|
||||
collector_MultipleTemplatesIntDouble.insert(self);
|
||||
}
|
||||
|
||||
void MultipleTemplatesIntDouble_deconstructor_90(int nargout, mxArray *out[], int nargin, const mxArray *in[])
|
||||
{
|
||||
typedef boost::shared_ptr<MultipleTemplates<int, double>> Shared;
|
||||
checkArguments("delete_MultipleTemplatesIntDouble",nargout,nargin,1);
|
||||
Shared *self = *reinterpret_cast<Shared**>(mxGetData(in[0]));
|
||||
Collector_MultipleTemplatesIntDouble::iterator item;
|
||||
item = collector_MultipleTemplatesIntDouble.find(self);
|
||||
if(item != collector_MultipleTemplatesIntDouble.end()) {
|
||||
delete self;
|
||||
collector_MultipleTemplatesIntDouble.erase(item);
|
||||
}
|
||||
}
|
||||
|
||||
void MultipleTemplatesIntFloat_collectorInsertAndMakeBase_91(int nargout, mxArray *out[], int nargin, const mxArray *in[])
|
||||
{
|
||||
mexAtExit(&_deleteAllObjects);
|
||||
typedef boost::shared_ptr<MultipleTemplates<int, float>> Shared;
|
||||
|
||||
Shared *self = *reinterpret_cast<Shared**> (mxGetData(in[0]));
|
||||
collector_MultipleTemplatesIntFloat.insert(self);
|
||||
}
|
||||
|
||||
void MultipleTemplatesIntFloat_deconstructor_92(int nargout, mxArray *out[], int nargin, const mxArray *in[])
|
||||
{
|
||||
typedef boost::shared_ptr<MultipleTemplates<int, float>> Shared;
|
||||
checkArguments("delete_MultipleTemplatesIntFloat",nargout,nargin,1);
|
||||
Shared *self = *reinterpret_cast<Shared**>(mxGetData(in[0]));
|
||||
Collector_MultipleTemplatesIntFloat::iterator item;
|
||||
item = collector_MultipleTemplatesIntFloat.find(self);
|
||||
if(item != collector_MultipleTemplatesIntFloat.end()) {
|
||||
delete self;
|
||||
collector_MultipleTemplatesIntFloat.erase(item);
|
||||
}
|
||||
}
|
||||
|
||||
void MyFactorPosePoint2_collectorInsertAndMakeBase_93(int nargout, mxArray *out[], int nargin, const mxArray *in[])
|
||||
{
|
||||
mexAtExit(&_deleteAllObjects);
|
||||
typedef boost::shared_ptr<MyFactor<gtsam::Pose2, gtsam::Matrix>> Shared;
|
||||
|
@ -1027,7 +1089,7 @@ void MyFactorPosePoint2_collectorInsertAndMakeBase_89(int nargout, mxArray *out[
|
|||
collector_MyFactorPosePoint2.insert(self);
|
||||
}
|
||||
|
||||
void MyFactorPosePoint2_constructor_90(int nargout, mxArray *out[], int nargin, const mxArray *in[])
|
||||
void MyFactorPosePoint2_constructor_94(int nargout, mxArray *out[], int nargin, const mxArray *in[])
|
||||
{
|
||||
mexAtExit(&_deleteAllObjects);
|
||||
typedef boost::shared_ptr<MyFactor<gtsam::Pose2, gtsam::Matrix>> Shared;
|
||||
|
@ -1042,7 +1104,7 @@ void MyFactorPosePoint2_constructor_90(int nargout, mxArray *out[], int nargin,
|
|||
*reinterpret_cast<Shared**> (mxGetData(out[0])) = self;
|
||||
}
|
||||
|
||||
void MyFactorPosePoint2_deconstructor_91(int nargout, mxArray *out[], int nargin, const mxArray *in[])
|
||||
void MyFactorPosePoint2_deconstructor_95(int nargout, mxArray *out[], int nargin, const mxArray *in[])
|
||||
{
|
||||
typedef boost::shared_ptr<MyFactor<gtsam::Pose2, gtsam::Matrix>> Shared;
|
||||
checkArguments("delete_MyFactorPosePoint2",nargout,nargin,1);
|
||||
|
@ -1055,7 +1117,7 @@ void MyFactorPosePoint2_deconstructor_91(int nargout, mxArray *out[], int nargin
|
|||
}
|
||||
}
|
||||
|
||||
void load2D_92(int nargout, mxArray *out[], int nargin, const mxArray *in[])
|
||||
void load2D_96(int nargout, mxArray *out[], int nargin, const mxArray *in[])
|
||||
{
|
||||
checkArguments("load2D",nargout,nargin,5);
|
||||
string filename = unwrap< string >(in[0]);
|
||||
|
@ -1067,7 +1129,7 @@ void load2D_92(int nargout, mxArray *out[], int nargin, const mxArray *in[])
|
|||
out[0] = wrap_shared_ptr(pairResult.first,"gtsam.NonlinearFactorGraph", false);
|
||||
out[1] = wrap_shared_ptr(pairResult.second,"gtsam.Values", false);
|
||||
}
|
||||
void load2D_93(int nargout, mxArray *out[], int nargin, const mxArray *in[])
|
||||
void load2D_97(int nargout, mxArray *out[], int nargin, const mxArray *in[])
|
||||
{
|
||||
checkArguments("load2D",nargout,nargin,5);
|
||||
string filename = unwrap< string >(in[0]);
|
||||
|
@ -1079,7 +1141,7 @@ void load2D_93(int nargout, mxArray *out[], int nargin, const mxArray *in[])
|
|||
out[0] = wrap_shared_ptr(pairResult.first,"gtsam.NonlinearFactorGraph", false);
|
||||
out[1] = wrap_shared_ptr(pairResult.second,"gtsam.Values", false);
|
||||
}
|
||||
void load2D_94(int nargout, mxArray *out[], int nargin, const mxArray *in[])
|
||||
void load2D_98(int nargout, mxArray *out[], int nargin, const mxArray *in[])
|
||||
{
|
||||
checkArguments("load2D",nargout,nargin,2);
|
||||
string filename = unwrap< string >(in[0]);
|
||||
|
@ -1088,18 +1150,18 @@ void load2D_94(int nargout, mxArray *out[], int nargin, const mxArray *in[])
|
|||
out[0] = wrap_shared_ptr(pairResult.first,"gtsam.NonlinearFactorGraph", false);
|
||||
out[1] = wrap_shared_ptr(pairResult.second,"gtsam.Values", false);
|
||||
}
|
||||
void aGlobalFunction_95(int nargout, mxArray *out[], int nargin, const mxArray *in[])
|
||||
void aGlobalFunction_99(int nargout, mxArray *out[], int nargin, const mxArray *in[])
|
||||
{
|
||||
checkArguments("aGlobalFunction",nargout,nargin,0);
|
||||
out[0] = wrap< Vector >(aGlobalFunction());
|
||||
}
|
||||
void overloadedGlobalFunction_96(int nargout, mxArray *out[], int nargin, const mxArray *in[])
|
||||
void overloadedGlobalFunction_100(int nargout, mxArray *out[], int nargin, const mxArray *in[])
|
||||
{
|
||||
checkArguments("overloadedGlobalFunction",nargout,nargin,1);
|
||||
int a = unwrap< int >(in[0]);
|
||||
out[0] = wrap< Vector >(overloadedGlobalFunction(a));
|
||||
}
|
||||
void overloadedGlobalFunction_97(int nargout, mxArray *out[], int nargin, const mxArray *in[])
|
||||
void overloadedGlobalFunction_101(int nargout, mxArray *out[], int nargin, const mxArray *in[])
|
||||
{
|
||||
checkArguments("overloadedGlobalFunction",nargout,nargin,2);
|
||||
int a = unwrap< int >(in[0]);
|
||||
|
@ -1356,16 +1418,16 @@ void mexFunction(int nargout, mxArray *out[], int nargin, const mxArray *in[])
|
|||
MyTemplateMatrix_Level_78(nargout, out, nargin-1, in+1);
|
||||
break;
|
||||
case 79:
|
||||
PrimitiveRefdouble_collectorInsertAndMakeBase_79(nargout, out, nargin-1, in+1);
|
||||
PrimitiveRefDouble_collectorInsertAndMakeBase_79(nargout, out, nargin-1, in+1);
|
||||
break;
|
||||
case 80:
|
||||
PrimitiveRefdouble_constructor_80(nargout, out, nargin-1, in+1);
|
||||
PrimitiveRefDouble_constructor_80(nargout, out, nargin-1, in+1);
|
||||
break;
|
||||
case 81:
|
||||
PrimitiveRefdouble_deconstructor_81(nargout, out, nargin-1, in+1);
|
||||
PrimitiveRefDouble_deconstructor_81(nargout, out, nargin-1, in+1);
|
||||
break;
|
||||
case 82:
|
||||
PrimitiveRefdouble_Brutal_82(nargout, out, nargin-1, in+1);
|
||||
PrimitiveRefDouble_Brutal_82(nargout, out, nargin-1, in+1);
|
||||
break;
|
||||
case 83:
|
||||
MyVector3_collectorInsertAndMakeBase_83(nargout, out, nargin-1, in+1);
|
||||
|
@ -1386,31 +1448,43 @@ void mexFunction(int nargout, mxArray *out[], int nargin, const mxArray *in[])
|
|||
MyVector12_deconstructor_88(nargout, out, nargin-1, in+1);
|
||||
break;
|
||||
case 89:
|
||||
MyFactorPosePoint2_collectorInsertAndMakeBase_89(nargout, out, nargin-1, in+1);
|
||||
MultipleTemplatesIntDouble_collectorInsertAndMakeBase_89(nargout, out, nargin-1, in+1);
|
||||
break;
|
||||
case 90:
|
||||
MyFactorPosePoint2_constructor_90(nargout, out, nargin-1, in+1);
|
||||
MultipleTemplatesIntDouble_deconstructor_90(nargout, out, nargin-1, in+1);
|
||||
break;
|
||||
case 91:
|
||||
MyFactorPosePoint2_deconstructor_91(nargout, out, nargin-1, in+1);
|
||||
MultipleTemplatesIntFloat_collectorInsertAndMakeBase_91(nargout, out, nargin-1, in+1);
|
||||
break;
|
||||
case 92:
|
||||
load2D_92(nargout, out, nargin-1, in+1);
|
||||
MultipleTemplatesIntFloat_deconstructor_92(nargout, out, nargin-1, in+1);
|
||||
break;
|
||||
case 93:
|
||||
load2D_93(nargout, out, nargin-1, in+1);
|
||||
MyFactorPosePoint2_collectorInsertAndMakeBase_93(nargout, out, nargin-1, in+1);
|
||||
break;
|
||||
case 94:
|
||||
load2D_94(nargout, out, nargin-1, in+1);
|
||||
MyFactorPosePoint2_constructor_94(nargout, out, nargin-1, in+1);
|
||||
break;
|
||||
case 95:
|
||||
aGlobalFunction_95(nargout, out, nargin-1, in+1);
|
||||
MyFactorPosePoint2_deconstructor_95(nargout, out, nargin-1, in+1);
|
||||
break;
|
||||
case 96:
|
||||
overloadedGlobalFunction_96(nargout, out, nargin-1, in+1);
|
||||
load2D_96(nargout, out, nargin-1, in+1);
|
||||
break;
|
||||
case 97:
|
||||
overloadedGlobalFunction_97(nargout, out, nargin-1, in+1);
|
||||
load2D_97(nargout, out, nargin-1, in+1);
|
||||
break;
|
||||
case 98:
|
||||
load2D_98(nargout, out, nargin-1, in+1);
|
||||
break;
|
||||
case 99:
|
||||
aGlobalFunction_99(nargout, out, nargin-1, in+1);
|
||||
break;
|
||||
case 100:
|
||||
overloadedGlobalFunction_100(nargout, out, nargin-1, in+1);
|
||||
break;
|
||||
case 101:
|
||||
overloadedGlobalFunction_101(nargout, out, nargin-1, in+1);
|
||||
break;
|
||||
}
|
||||
} catch(const std::exception& e) {
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
function varargout = load2D(varargin)
|
||||
if length(varargin) == 5 && isa(varargin{1},'char') && isa(varargin{2},'Test') && isa(varargin{3},'numeric') && isa(varargin{4},'logical') && isa(varargin{5},'logical')
|
||||
[ varargout{1} varargout{2} ] = geometry_wrapper(92, varargin{:});
|
||||
[ varargout{1} varargout{2} ] = geometry_wrapper(96, varargin{:});
|
||||
elseif length(varargin) == 5 && isa(varargin{1},'char') && isa(varargin{2},'gtsam.noiseModel.Diagonal') && isa(varargin{3},'numeric') && isa(varargin{4},'logical') && isa(varargin{5},'logical')
|
||||
[ varargout{1} varargout{2} ] = geometry_wrapper(93, varargin{:});
|
||||
[ varargout{1} varargout{2} ] = geometry_wrapper(97, varargin{:});
|
||||
elseif length(varargin) == 2 && isa(varargin{1},'char') && isa(varargin{2},'gtsam.noiseModel.Diagonal')
|
||||
[ varargout{1} varargout{2} ] = geometry_wrapper(94, varargin{:});
|
||||
[ varargout{1} varargout{2} ] = geometry_wrapper(98, varargin{:});
|
||||
else
|
||||
error('Arguments do not match any overload of function load2D');
|
||||
end
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
function varargout = overloadedGlobalFunction(varargin)
|
||||
if length(varargin) == 1 && isa(varargin{1},'numeric')
|
||||
varargout{1} = geometry_wrapper(96, varargin{:});
|
||||
varargout{1} = geometry_wrapper(100, varargin{:});
|
||||
elseif length(varargin) == 2 && isa(varargin{1},'numeric') && isa(varargin{2},'double')
|
||||
varargout{1} = geometry_wrapper(97, varargin{:});
|
||||
varargout{1} = geometry_wrapper(101, varargin{:});
|
||||
else
|
||||
error('Arguments do not match any overload of function overloadedGlobalFunction');
|
||||
end
|
||||
|
|
|
@ -115,7 +115,8 @@ PYBIND11_MODULE(geometry_py, m_) {
|
|||
gtsam::RedirectCout redirect;
|
||||
a.print();
|
||||
return redirect.str();
|
||||
});
|
||||
})
|
||||
.def_readwrite("model_ptr", &Test::model_ptr);
|
||||
|
||||
py::class_<MyBase, std::shared_ptr<MyBase>>(m_, "MyBase");
|
||||
|
||||
|
@ -149,7 +150,7 @@ PYBIND11_MODULE(geometry_py, m_) {
|
|||
.def("return_ptrs",[](MyTemplate<gtsam::Matrix>* self,const std::shared_ptr<gtsam::Matrix>& p1,const std::shared_ptr<gtsam::Matrix>& p2){return self->return_ptrs(p1, p2);}, py::arg("p1"), py::arg("p2"))
|
||||
.def_static("Level",[](const gtsam::Matrix& K){return MyTemplate<gtsam::Matrix>::Level(K);}, py::arg("K"));
|
||||
|
||||
py::class_<PrimitiveRef<double>, std::shared_ptr<PrimitiveRef<double>>>(m_, "PrimitiveRefdouble")
|
||||
py::class_<PrimitiveRef<double>, std::shared_ptr<PrimitiveRef<double>>>(m_, "PrimitiveRefDouble")
|
||||
.def(py::init<>())
|
||||
.def_static("Brutal",[](const double& t){return PrimitiveRef<double>::Brutal(t);}, py::arg("t"));
|
||||
|
||||
|
@ -159,6 +160,10 @@ PYBIND11_MODULE(geometry_py, m_) {
|
|||
py::class_<MyVector<12>, std::shared_ptr<MyVector<12>>>(m_, "MyVector12")
|
||||
.def(py::init<>());
|
||||
|
||||
py::class_<MultipleTemplates<int, double>, std::shared_ptr<MultipleTemplates<int, double>>>(m_, "MultipleTemplatesIntDouble");
|
||||
|
||||
py::class_<MultipleTemplates<int, float>, std::shared_ptr<MultipleTemplates<int, float>>>(m_, "MultipleTemplatesIntFloat");
|
||||
|
||||
py::class_<MyFactor<gtsam::Pose2, gtsam::Matrix>, std::shared_ptr<MyFactor<gtsam::Pose2, gtsam::Matrix>>>(m_, "MyFactorPosePoint2")
|
||||
.def(py::init< size_t, size_t, double, const std::shared_ptr<gtsam::noiseModel::Base>&>(), py::arg("key1"), py::arg("key2"), py::arg("measured"), py::arg("noiseModel"));
|
||||
|
||||
|
|
|
@ -61,6 +61,9 @@ class Test {
|
|||
// another comment
|
||||
Test();
|
||||
|
||||
// Test a shared ptr property
|
||||
gtsam::noiseModel::Base* model_ptr;
|
||||
|
||||
pair<Vector,Matrix> return_pair (Vector v, Matrix A) const; // intentionally the first method
|
||||
pair<Vector,Matrix> return_pair (Vector v) const; // overload
|
||||
|
||||
|
@ -160,3 +163,7 @@ class MyVector {
|
|||
// comments at the end!
|
||||
|
||||
// even more comments at the end!
|
||||
|
||||
// Class with multiple instantiated templates
|
||||
template<T = {int}, U = {double, float}>
|
||||
class MultipleTemplates {};
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
|
||||
{boost_class_export}
|
||||
|
||||
{hoder_type}
|
||||
{holder_type}
|
||||
|
||||
using namespace std;
|
||||
|
||||
|
|
|
@ -1,21 +1,26 @@
|
|||
"""
|
||||
Unit test for Matlab wrap program
|
||||
Author: Matthew Sklar
|
||||
Unit tests for Matlab wrap program
|
||||
Author: Matthew Sklar, Varun Agrawal
|
||||
Date: March 2019
|
||||
"""
|
||||
# pylint: disable=import-error, wrong-import-position, too-many-branches
|
||||
|
||||
import filecmp
|
||||
import os
|
||||
import sys
|
||||
import unittest
|
||||
import filecmp
|
||||
|
||||
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
||||
|
||||
import gtwrap.template_instantiator as instantiator
|
||||
import gtwrap.interface_parser as parser
|
||||
import gtwrap.template_instantiator as instantiator
|
||||
from gtwrap.matlab_wrapper import MatlabWrapper
|
||||
|
||||
|
||||
class TestWrap(unittest.TestCase):
|
||||
"""
|
||||
Test the Matlab wrapper
|
||||
"""
|
||||
TEST_DIR = os.path.dirname(os.path.realpath(__file__)) + "/"
|
||||
MATLAB_TEST_DIR = TEST_DIR + "expected-matlab/"
|
||||
MATLAB_ACTUAL_DIR = TEST_DIR + "actual-matlab/"
|
||||
|
@ -31,11 +36,11 @@ class TestWrap(unittest.TestCase):
|
|||
"""
|
||||
if path == '':
|
||||
path = self.MATLAB_ACTUAL_DIR
|
||||
|
||||
for c in cc_content:
|
||||
if type(c) == list:
|
||||
if isinstance(c, list):
|
||||
if len(c) == 0:
|
||||
continue
|
||||
import sys
|
||||
print("c object: {}".format(c[0][0]), file=sys.stderr)
|
||||
path_to_folder = path + '/' + c[0][0]
|
||||
|
||||
|
@ -46,13 +51,12 @@ class TestWrap(unittest.TestCase):
|
|||
pass
|
||||
|
||||
for sub_content in c:
|
||||
import sys
|
||||
print("sub object: {}".format(sub_content[1][0][0]), file=sys.stderr)
|
||||
self.generate_content(sub_content[1], path_to_folder)
|
||||
elif type(c[1]) == list:
|
||||
|
||||
elif isinstance(c[1], list):
|
||||
path_to_folder = path + '/' + c[0]
|
||||
|
||||
import sys
|
||||
print("[generate_content_global]: {}".format(path_to_folder), file=sys.stderr)
|
||||
if not os.path.isdir(path_to_folder):
|
||||
try:
|
||||
|
@ -60,15 +64,14 @@ class TestWrap(unittest.TestCase):
|
|||
except OSError:
|
||||
pass
|
||||
for sub_content in c[1]:
|
||||
import sys
|
||||
path_to_file = path_to_folder + '/' + sub_content[0]
|
||||
print("[generate_global_method]: {}".format(path_to_file), file=sys.stderr)
|
||||
with open(path_to_file, 'w') as f:
|
||||
f.write(sub_content[1])
|
||||
|
||||
else:
|
||||
path_to_file = path + '/' + c[0]
|
||||
|
||||
import sys
|
||||
print("[generate_content]: {}".format(path_to_file), file=sys.stderr)
|
||||
if not os.path.isdir(path_to_file):
|
||||
try:
|
||||
|
@ -80,7 +83,8 @@ class TestWrap(unittest.TestCase):
|
|||
f.write(c[1])
|
||||
|
||||
def test_geometry_matlab(self):
|
||||
""" Check generation of matlab geometry wrapper.
|
||||
"""
|
||||
Check generation of matlab geometry wrapper.
|
||||
python3 wrap/matlab_wrapper.py --src wrap/tests/geometry.h
|
||||
--module_name geometry --out wrap/tests/actual-matlab
|
||||
"""
|
||||
|
|
|
@ -1,27 +1,29 @@
|
|||
"""
|
||||
Unit test for Pybind wrap program
|
||||
Author: Matthew Sklar
|
||||
Author: Matthew Sklar, Varun Agrawal
|
||||
Date: February 2019
|
||||
"""
|
||||
|
||||
# pylint: disable=import-error, wrong-import-position, too-many-branches
|
||||
|
||||
import filecmp
|
||||
import os
|
||||
import os.path as path
|
||||
import sys
|
||||
import unittest
|
||||
import filecmp
|
||||
|
||||
import os.path as path
|
||||
|
||||
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
||||
sys.path.append(os.path.normpath(os.path.abspath(os.path.join(__file__, '../../../build/wrap'))))
|
||||
|
||||
from gtwrap.pybind_wrapper import PybindWrapper
|
||||
import gtwrap.interface_parser as parser
|
||||
import gtwrap.template_instantiator as instantiator
|
||||
from gtwrap.pybind_wrapper import PybindWrapper
|
||||
|
||||
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
||||
|
||||
|
||||
class TestWrap(unittest.TestCase):
|
||||
"""Tests for Python wrapper based on Pybind11."""
|
||||
TEST_DIR = os.path.dirname(os.path.realpath(__file__)) + "/"
|
||||
|
||||
def test_geometry_python(self):
|
||||
|
@ -39,7 +41,7 @@ class TestWrap(unittest.TestCase):
|
|||
|
||||
with open(self.TEST_DIR + "pybind_wrapper.tpl") as template_file:
|
||||
module_template = template_file.read()
|
||||
|
||||
|
||||
# Create Pybind wrapper instance
|
||||
wrapper = PybindWrapper(
|
||||
module=module,
|
||||
|
|
Loading…
Reference in New Issue