Merging 'master' into 'wrap'
commit
f81746da20
|
@ -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.
|
|
@ -3,12 +3,14 @@
|
||||||
The wrap library wraps the GTSAM library into a Python library or MATLAB toolbox.
|
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.
|
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.
|
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.
|
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
|
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).
|
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
|
## Python Wrapper
|
||||||
|
|
||||||
**WARNING: On macOS, you have to statically build GTSAM to use the 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:
|
1. Just run python then import GTSAM and play around:
|
||||||
|
|
||||||
```
|
```python
|
||||||
import gtsam
|
import gtsam
|
||||||
gtsam.__dir__()
|
gtsam.__dir__()
|
||||||
```
|
```
|
||||||
|
|
||||||
1. Run the unittests:
|
1. Run the unittests:
|
||||||
```
|
```sh
|
||||||
python -m unittest discover
|
python -m unittest discover
|
||||||
```
|
```
|
||||||
1. Edit the unittests in `python/gtsam/*.py` and simply rerun the test.
|
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. Do `make install` and `cd <gtsam_install_folder>/python`. Here, you can:
|
||||||
1. Run the unittests:
|
1. Run the unittests:
|
||||||
```
|
```sh
|
||||||
python setup.py test
|
python setup.py test
|
||||||
```
|
```
|
||||||
2. Install `gtsam` to your current Python environment.
|
2. Install `gtsam` to your current Python environment.
|
||||||
```
|
```sh
|
||||||
python setup.py install
|
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.
|
- 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
|
See LICENSE for the license information
|
||||||
|
|
||||||
Parser to get the interface of a C++ source file
|
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 (
|
# pylint: disable=unnecessary-lambda, unused-import, expression-not-assigned, no-else-return, protected-access, too-few-public-methods, too-many-arguments
|
||||||
alphas,
|
|
||||||
alphanums,
|
import typing
|
||||||
cppStyleComment,
|
|
||||||
delimitedList,
|
from pyparsing import (CharsNotIn, Forward, Group, Keyword, Literal, OneOrMore,
|
||||||
empty,
|
Optional, Or, ParseException, ParserElement, Suppress,
|
||||||
nums,
|
Word, ZeroOrMore, alphanums, alphas, cppStyleComment,
|
||||||
stringEnd,
|
delimitedList, empty, nums, stringEnd)
|
||||||
CharsNotIn,
|
|
||||||
Forward,
|
|
||||||
Group,
|
|
||||||
Keyword,
|
|
||||||
Literal,
|
|
||||||
OneOrMore,
|
|
||||||
Optional,
|
|
||||||
Or,
|
|
||||||
ParseException,
|
|
||||||
ParserElement,
|
|
||||||
Suppress,
|
|
||||||
Word,
|
|
||||||
ZeroOrMore,
|
|
||||||
)
|
|
||||||
|
|
||||||
ParserElement.enablePackrat()
|
ParserElement.enablePackrat()
|
||||||
|
|
||||||
|
# rule for identifiers (e.g. variable names)
|
||||||
IDENT = Word(alphas + '_', alphanums + '_') ^ Word(nums)
|
IDENT = Word(alphas + '_', alphanums + '_') ^ Word(nums)
|
||||||
|
|
||||||
POINTER, REF = map(Literal, "*&")
|
POINTER, REF = map(Literal, "*&")
|
||||||
LPAREN, RPAREN, LBRACE, RBRACE, COLON, SEMI_COLON = map(Suppress, "(){}:;")
|
LPAREN, RPAREN, LBRACE, RBRACE, COLON, SEMI_COLON = map(Suppress, "(){}:;")
|
||||||
LOPBRACK, ROPBRACK, COMMA, EQUAL = 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, "::")
|
namespaces_name_rule = delimitedList(IDENT, "::")
|
||||||
|
@ -86,34 +72,38 @@ class Typename(object):
|
||||||
)
|
)
|
||||||
).setParseAction(lambda t: Typename(t.namespaces_name, t.instantiations))
|
).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.namespaces = namespaces_name[:-1]
|
||||||
self.name = namespaces_name[-1]
|
self.name = namespaces_name[-1]
|
||||||
|
|
||||||
if instantiations:
|
if instantiations:
|
||||||
if not isinstance(instantiations, list):
|
if not isinstance(instantiations, typing.Iterable):
|
||||||
self.instantiations = instantiations.asList()
|
self.instantiations = instantiations.asList()
|
||||||
else:
|
else:
|
||||||
self.instantiations = instantiations
|
self.instantiations = instantiations
|
||||||
else:
|
else:
|
||||||
self.instantiations = []
|
self.instantiations = []
|
||||||
|
|
||||||
if self.name in ["Matrix", "Vector"] and not self.namespaces:
|
if self.name in ["Matrix", "Vector"] and not self.namespaces:
|
||||||
self.namespaces = ["gtsam"]
|
self.namespaces = ["gtsam"]
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def from_parse_result(parse_result):
|
def from_parse_result(parse_result):
|
||||||
|
"""Return the typename from the parsed result."""
|
||||||
return parse_result[0]
|
return parse_result[0]
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return self.to_cpp()
|
return self.to_cpp()
|
||||||
|
|
||||||
def instantiated_name(self):
|
def instantiated_name(self):
|
||||||
|
"""Get the instantiated name of the type."""
|
||||||
res = self.name
|
res = self.name
|
||||||
for instantiation in self.instantiations:
|
for instantiation in self.instantiations:
|
||||||
res += instantiation.instantiated_name()
|
res += instantiation.instantiated_name()
|
||||||
return res
|
return res
|
||||||
|
|
||||||
def to_cpp(self):
|
def to_cpp(self):
|
||||||
|
"""Generate the C++ code for wrapping."""
|
||||||
idx = 1 if self.namespaces and not self.namespaces[0] else 0
|
idx = 1 if self.namespaces and not self.namespaces[0] else 0
|
||||||
if self.instantiations:
|
if self.instantiations:
|
||||||
cpp_name = self.name + "<{}>".format(
|
cpp_name = self.name + "<{}>".format(
|
||||||
|
@ -140,8 +130,11 @@ class Typename(object):
|
||||||
return not res
|
return not res
|
||||||
|
|
||||||
|
|
||||||
class Type(object):
|
class Type:
|
||||||
class _QualifiedType(object):
|
"""
|
||||||
|
The type value that is parsed, e.g. void, string, size_t.
|
||||||
|
"""
|
||||||
|
class _QualifiedType:
|
||||||
"""
|
"""
|
||||||
Type with qualifiers.
|
Type with qualifiers.
|
||||||
"""
|
"""
|
||||||
|
@ -165,7 +158,7 @@ class Type(object):
|
||||||
self.is_ptr = is_ptr
|
self.is_ptr = is_ptr
|
||||||
self.is_ref = is_ref
|
self.is_ref = is_ref
|
||||||
|
|
||||||
class _BasisType(object):
|
class _BasisType:
|
||||||
"""
|
"""
|
||||||
Basis types don't have qualifiers and only allow copy-by-value.
|
Basis types don't have qualifiers and only allow copy-by-value.
|
||||||
"""
|
"""
|
||||||
|
@ -185,6 +178,7 @@ class Type(object):
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def from_parse_result(t):
|
def from_parse_result(t):
|
||||||
|
"""Return the resulting Type from parsing the source."""
|
||||||
if t.basis:
|
if t.basis:
|
||||||
return Type(
|
return Type(
|
||||||
typename=t.basis,
|
typename=t.basis,
|
||||||
|
@ -211,6 +205,8 @@ class Type(object):
|
||||||
|
|
||||||
def to_cpp(self, use_boost):
|
def to_cpp(self, use_boost):
|
||||||
"""
|
"""
|
||||||
|
Generate the C++ code for wrapping.
|
||||||
|
|
||||||
Treat all pointers as "const shared_ptr<T>&"
|
Treat all pointers as "const shared_ptr<T>&"
|
||||||
Treat Matrix and Vector as "const Matrix&" and "const Vector&" resp.
|
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(
|
rule = (Type.rule("ctype") + IDENT("name")).setParseAction(
|
||||||
lambda t: Argument(t.ctype, t.name)
|
lambda t: Argument(t.ctype, t.name)
|
||||||
)
|
)
|
||||||
|
@ -250,7 +254,10 @@ class Argument(object):
|
||||||
return '{} {}'.format(self.ctype.__repr__(), self.name)
|
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(
|
rule = Optional(delimitedList(Argument.rule)("args_list")).setParseAction(
|
||||||
lambda t: ArgumentList.from_parse_result(t.args_list)
|
lambda t: ArgumentList.from_parse_result(t.args_list)
|
||||||
)
|
)
|
||||||
|
@ -262,6 +269,7 @@ class ArgumentList(object):
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def from_parse_result(parse_result):
|
def from_parse_result(parse_result):
|
||||||
|
"""Return the result of parsing."""
|
||||||
if parse_result:
|
if parse_result:
|
||||||
return ArgumentList(parse_result.asList())
|
return ArgumentList(parse_result.asList())
|
||||||
else:
|
else:
|
||||||
|
@ -271,13 +279,20 @@ class ArgumentList(object):
|
||||||
return self.args_list.__repr__()
|
return self.args_list.__repr__()
|
||||||
|
|
||||||
def args_names(self):
|
def args_names(self):
|
||||||
|
"""Return a list of the names of all the arguments."""
|
||||||
return [arg.name for arg in self.args_list]
|
return [arg.name for arg in self.args_list]
|
||||||
|
|
||||||
def to_cpp(self, use_boost):
|
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]
|
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 = (
|
||||||
PAIR.suppress()
|
PAIR.suppress()
|
||||||
+ LOPBRACK
|
+ LOPBRACK
|
||||||
|
@ -295,6 +310,9 @@ class ReturnType(object):
|
||||||
self.type2 = type2
|
self.type2 = type2
|
||||||
|
|
||||||
def is_void(self):
|
def is_void(self):
|
||||||
|
"""
|
||||||
|
Check if the return type is void.
|
||||||
|
"""
|
||||||
return self.type1.typename.name == "void" and not self.type2
|
return self.type1.typename.name == "void" and not self.type2
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
|
@ -303,6 +321,7 @@ class ReturnType(object):
|
||||||
)
|
)
|
||||||
|
|
||||||
def to_cpp(self):
|
def to_cpp(self):
|
||||||
|
"""Generate the C++ code for wrapping."""
|
||||||
if self.type2:
|
if self.type2:
|
||||||
return "std::pair<{type1},{type2}>".format(
|
return "std::pair<{type1},{type2}>".format(
|
||||||
type1=self.type1.to_cpp(), type2=self.type2.to_cpp()
|
type1=self.type1.to_cpp(), type2=self.type2.to_cpp()
|
||||||
|
@ -311,8 +330,20 @@ class ReturnType(object):
|
||||||
return self.type1.to_cpp()
|
return self.type1.to_cpp()
|
||||||
|
|
||||||
|
|
||||||
class Template(object):
|
class Template:
|
||||||
class TypenameAndInstantiations(object):
|
"""
|
||||||
|
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 = (
|
rule = (
|
||||||
IDENT("typename")
|
IDENT("typename")
|
||||||
+ Optional(
|
+ Optional(
|
||||||
|
@ -351,8 +382,21 @@ class Template(object):
|
||||||
self.typenames = [ti.typename for ti in ti_list]
|
self.typenames = [ti.typename for ti in ti_list]
|
||||||
self.instantiations = [ti.instantiations 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 = (
|
rule = (
|
||||||
Optional(Template.rule("template"))
|
Optional(Template.rule("template"))
|
||||||
+ ReturnType.rule("return_type")
|
+ 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 = (
|
rule = (
|
||||||
STATIC
|
STATIC
|
||||||
+ ReturnType.rule("return_type")
|
+ ReturnType.rule("return_type")
|
||||||
|
@ -411,10 +465,15 @@ class StaticMethod(object):
|
||||||
return "static {} {}{}".format(self.return_type, self.name, self.args)
|
return "static {} {}{}".format(self.return_type, self.name, self.args)
|
||||||
|
|
||||||
def to_cpp(self):
|
def to_cpp(self):
|
||||||
|
"""Generate the C++ code for wrapping."""
|
||||||
return self.name
|
return self.name
|
||||||
|
|
||||||
|
|
||||||
class Constructor(object):
|
class Constructor:
|
||||||
|
"""
|
||||||
|
Rule to parse the class constructor.
|
||||||
|
Can have 0 or more arguments.
|
||||||
|
"""
|
||||||
rule = (
|
rule = (
|
||||||
IDENT("name")
|
IDENT("name")
|
||||||
+ LPAREN
|
+ LPAREN
|
||||||
|
@ -433,7 +492,17 @@ class Constructor(object):
|
||||||
return "Constructor: {}".format(self.name)
|
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(
|
rule = (Type.rule("ctype") + IDENT("name") + SEMI_COLON).setParseAction(
|
||||||
lambda t: Property(t.ctype, t.name)
|
lambda t: Property(t.ctype, t.name)
|
||||||
)
|
)
|
||||||
|
@ -441,10 +510,6 @@ class Property(object):
|
||||||
def __init__(self, ctype, name, parent=''):
|
def __init__(self, ctype, name, parent=''):
|
||||||
self.ctype = ctype
|
self.ctype = ctype
|
||||||
self.name = name
|
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
|
self.parent = parent
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
|
@ -452,6 +517,7 @@ class Property(object):
|
||||||
|
|
||||||
|
|
||||||
def collect_namespaces(obj):
|
def collect_namespaces(obj):
|
||||||
|
"""Get the chain of namespaces from the lowest to highest for the given object."""
|
||||||
namespaces = []
|
namespaces = []
|
||||||
ancestor = obj.parent
|
ancestor = obj.parent
|
||||||
while ancestor and ancestor.name:
|
while ancestor and ancestor.name:
|
||||||
|
@ -460,8 +526,21 @@ def collect_namespaces(obj):
|
||||||
return [''] + namespaces
|
return [''] + namespaces
|
||||||
|
|
||||||
|
|
||||||
class Class(object):
|
class Class:
|
||||||
class MethodsAndProperties(object):
|
"""
|
||||||
|
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(
|
rule = ZeroOrMore(
|
||||||
Constructor.rule ^ StaticMethod.rule ^ Method.rule ^ Property.rule
|
Constructor.rule ^ StaticMethod.rule ^ Method.rule ^ Property.rule
|
||||||
).setParseAction(lambda t: Class.MethodsAndProperties(t.asList()))
|
).setParseAction(lambda t: Class.MethodsAndProperties(t.asList()))
|
||||||
|
@ -549,10 +628,19 @@ class Class(object):
|
||||||
_property.parent = self
|
_property.parent = self
|
||||||
|
|
||||||
def namespaces(self):
|
def namespaces(self):
|
||||||
|
"""Get the namespaces which this class is nested under as a list."""
|
||||||
return collect_namespaces(self)
|
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 = (
|
rule = (
|
||||||
TYPEDEF + Typename.rule("typename") + IDENT("new_name") + SEMI_COLON
|
TYPEDEF + Typename.rule("typename") + IDENT("new_name") + SEMI_COLON
|
||||||
).setParseAction(
|
).setParseAction(
|
||||||
|
@ -567,7 +655,10 @@ class TypedefTemplateInstantiation(object):
|
||||||
self.parent = parent
|
self.parent = parent
|
||||||
|
|
||||||
|
|
||||||
class Include(object):
|
class Include:
|
||||||
|
"""
|
||||||
|
Rule to parse #include directives.
|
||||||
|
"""
|
||||||
rule = (
|
rule = (
|
||||||
INCLUDE + LOPBRACK + CharsNotIn('>')("header") + ROPBRACK
|
INCLUDE + LOPBRACK + CharsNotIn('>')("header") + ROPBRACK
|
||||||
).setParseAction(lambda t: Include(t.header))
|
).setParseAction(lambda t: Include(t.header))
|
||||||
|
@ -580,7 +671,10 @@ class Include(object):
|
||||||
return "#include <{}>".format(self.header)
|
return "#include <{}>".format(self.header)
|
||||||
|
|
||||||
|
|
||||||
class ForwardDeclaration(object):
|
class ForwardDeclaration:
|
||||||
|
"""
|
||||||
|
Rule to parse forward declarations in the interface file.
|
||||||
|
"""
|
||||||
rule = (
|
rule = (
|
||||||
Optional(VIRTUAL("is_virtual"))
|
Optional(VIRTUAL("is_virtual"))
|
||||||
+ CLASS
|
+ CLASS
|
||||||
|
@ -606,7 +700,10 @@ class ForwardDeclaration(object):
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class GlobalFunction(object):
|
class GlobalFunction:
|
||||||
|
"""
|
||||||
|
Rule to parse functions defined in the global scope.
|
||||||
|
"""
|
||||||
rule = (
|
rule = (
|
||||||
ReturnType.rule("return_type")
|
ReturnType.rule("return_type")
|
||||||
+ IDENT("name")
|
+ IDENT("name")
|
||||||
|
@ -634,10 +731,18 @@ class GlobalFunction(object):
|
||||||
)
|
)
|
||||||
|
|
||||||
def to_cpp(self):
|
def to_cpp(self):
|
||||||
|
"""Generate the C++ code for wrapping."""
|
||||||
return self.name
|
return self.name
|
||||||
|
|
||||||
|
|
||||||
def find_sub_namespace(namespace, str_namespaces):
|
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:
|
if not str_namespaces:
|
||||||
return [namespace]
|
return [namespace]
|
||||||
|
|
||||||
|
@ -659,7 +764,8 @@ def find_sub_namespace(namespace, str_namespaces):
|
||||||
return res
|
return res
|
||||||
|
|
||||||
|
|
||||||
class Namespace(object):
|
class Namespace:
|
||||||
|
"""Rule for parsing a namespace in the interface file."""
|
||||||
rule = Forward()
|
rule = Forward()
|
||||||
rule << (
|
rule << (
|
||||||
NAMESPACE
|
NAMESPACE
|
||||||
|
@ -687,6 +793,7 @@ class Namespace(object):
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def from_parse_result(t):
|
def from_parse_result(t):
|
||||||
|
"""Return the result of parsing."""
|
||||||
if t.content:
|
if t.content:
|
||||||
content = t.content.asList()
|
content = t.content.asList()
|
||||||
else:
|
else:
|
||||||
|
@ -717,6 +824,7 @@ class Namespace(object):
|
||||||
return res[0]
|
return res[0]
|
||||||
|
|
||||||
def top_level(self):
|
def top_level(self):
|
||||||
|
"""Return the top leve namespace."""
|
||||||
if self.name == '' or self.parent == '':
|
if self.name == '' or self.parent == '':
|
||||||
return self
|
return self
|
||||||
else:
|
else:
|
||||||
|
@ -726,15 +834,23 @@ class Namespace(object):
|
||||||
return "Namespace: {}\n\t{}".format(self.name, self.content)
|
return "Namespace: {}\n\t{}".format(self.name, self.content)
|
||||||
|
|
||||||
def full_namespaces(self):
|
def full_namespaces(self):
|
||||||
|
"""Get the full namespace list."""
|
||||||
ancestors = collect_namespaces(self)
|
ancestors = collect_namespaces(self)
|
||||||
if self.name:
|
if self.name:
|
||||||
ancestors.append(self.name)
|
ancestors.append(self.name)
|
||||||
return ancestors
|
return ancestors
|
||||||
|
|
||||||
|
|
||||||
class Module(object):
|
class Module:
|
||||||
"""
|
"""
|
||||||
Module is just a global namespace.
|
Module is just a global namespace.
|
||||||
|
|
||||||
|
E.g.
|
||||||
|
```
|
||||||
|
namespace gtsam {
|
||||||
|
...
|
||||||
|
}
|
||||||
|
```
|
||||||
"""
|
"""
|
||||||
|
|
||||||
rule = (
|
rule = (
|
||||||
|
@ -752,5 +868,6 @@ class Module(object):
|
||||||
rule.ignore(cppStyleComment)
|
rule.ignore(cppStyleComment)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def parseString(str):
|
def parseString(s: str):
|
||||||
return Module.rule.parseString(str)[0]
|
"""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
|
See LICENSE for the license information
|
||||||
|
|
||||||
Code generator for wrapping a C++ module with Pybind11
|
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 re
|
||||||
import textwrap
|
import textwrap
|
||||||
|
|
||||||
|
@ -16,13 +19,16 @@ import gtwrap.interface_parser as parser
|
||||||
import gtwrap.template_instantiator as instantiator
|
import gtwrap.template_instantiator as instantiator
|
||||||
|
|
||||||
|
|
||||||
class PybindWrapper(object):
|
class PybindWrapper:
|
||||||
|
"""
|
||||||
|
Class to generate binding code for Pybind11 specifically.
|
||||||
|
"""
|
||||||
def __init__(self,
|
def __init__(self,
|
||||||
module,
|
module,
|
||||||
module_name,
|
module_name,
|
||||||
top_module_namespaces='',
|
top_module_namespaces='',
|
||||||
use_boost=False,
|
use_boost=False,
|
||||||
ignore_classes=[],
|
ignore_classes=(),
|
||||||
module_template=""):
|
module_template=""):
|
||||||
self.module = module
|
self.module = module
|
||||||
self.module_name = module_name
|
self.module_name = module_name
|
||||||
|
@ -34,6 +40,7 @@ class PybindWrapper(object):
|
||||||
self.python_keywords = ['print', 'lambda']
|
self.python_keywords = ['print', 'lambda']
|
||||||
|
|
||||||
def _py_args_names(self, args_list):
|
def _py_args_names(self, args_list):
|
||||||
|
"""Set the argument names in Pybind11 format."""
|
||||||
names = args_list.args_names()
|
names = args_list.args_names()
|
||||||
if names:
|
if names:
|
||||||
py_args = ['py::arg("{}")'.format(name) for name in names]
|
py_args = ['py::arg("{}")'.format(name) for name in names]
|
||||||
|
@ -42,6 +49,7 @@ class PybindWrapper(object):
|
||||||
return ''
|
return ''
|
||||||
|
|
||||||
def _method_args_signature_with_names(self, args_list):
|
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)
|
cpp_types = args_list.to_cpp(self.use_boost)
|
||||||
names = args_list.args_names()
|
names = args_list.args_names()
|
||||||
types_names = ["{} {}".format(ctype, name) for ctype, name in zip(cpp_types, 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)
|
return ','.join(types_names)
|
||||||
|
|
||||||
def wrap_ctors(self, my_class):
|
def wrap_ctors(self, my_class):
|
||||||
|
"""Wrap the constructors."""
|
||||||
res = ""
|
res = ""
|
||||||
for ctor in my_class.ctors:
|
for ctor in my_class.ctors:
|
||||||
res += ('\n' + ' ' * 8 + '.def(py::init<{args_cpp_types}>()'
|
res += ('\n' + ' ' * 8 + '.def(py::init<{args_cpp_types}>()'
|
||||||
|
@ -115,8 +124,10 @@ class PybindWrapper(object):
|
||||||
'{py_args_names}){suffix}'.format(
|
'{py_args_names}){suffix}'.format(
|
||||||
prefix=prefix,
|
prefix=prefix,
|
||||||
cdef="def_static" if is_static else "def",
|
cdef="def_static" if is_static else "def",
|
||||||
py_method=py_method if not py_method in self.python_keywords else py_method + "_",
|
py_method=py_method if not py_method in self.python_keywords
|
||||||
opt_self="{cpp_class}* self".format(cpp_class=cpp_class) if is_method else "",
|
else py_method + "_",
|
||||||
|
opt_self="{cpp_class}* self".format(
|
||||||
|
cpp_class=cpp_class) if is_method else "",
|
||||||
cpp_class=cpp_class,
|
cpp_class=cpp_class,
|
||||||
cpp_method=cpp_method,
|
cpp_method=cpp_method,
|
||||||
opt_comma=',' if is_method and args_names else '',
|
opt_comma=',' if is_method and args_names else '',
|
||||||
|
@ -152,6 +163,7 @@ class PybindWrapper(object):
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
def wrap_methods(self, methods, cpp_class, prefix='\n' + ' ' * 8, suffix=''):
|
def wrap_methods(self, methods, cpp_class, prefix='\n' + ' ' * 8, suffix=''):
|
||||||
|
"""Wrap all the methods in the `cpp_class`."""
|
||||||
res = ""
|
res = ""
|
||||||
for method in methods:
|
for method in methods:
|
||||||
|
|
||||||
|
@ -176,6 +188,7 @@ class PybindWrapper(object):
|
||||||
return res
|
return res
|
||||||
|
|
||||||
def wrap_properties(self, properties, cpp_class, prefix='\n' + ' ' * 8):
|
def wrap_properties(self, properties, cpp_class, prefix='\n' + ' ' * 8):
|
||||||
|
"""Wrap all the properties in the `cpp_class`."""
|
||||||
res = ""
|
res = ""
|
||||||
for prop in properties:
|
for prop in properties:
|
||||||
res += ('{prefix}.def_{property}("{property_name}", '
|
res += ('{prefix}.def_{property}("{property_name}", '
|
||||||
|
@ -188,50 +201,61 @@ class PybindWrapper(object):
|
||||||
return res
|
return res
|
||||||
|
|
||||||
def wrap_instantiated_class(self, instantiated_class):
|
def wrap_instantiated_class(self, instantiated_class):
|
||||||
|
"""Wrap the class."""
|
||||||
module_var = self._gen_module_var(instantiated_class.namespaces())
|
module_var = self._gen_module_var(instantiated_class.namespaces())
|
||||||
cpp_class = instantiated_class.cpp_class()
|
cpp_class = instantiated_class.cpp_class()
|
||||||
if cpp_class in self.ignore_classes:
|
if cpp_class in self.ignore_classes:
|
||||||
return ""
|
return ""
|
||||||
return ('\n py::class_<{cpp_class}, {class_parent}'
|
return (
|
||||||
'{shared_ptr_type}::shared_ptr<{cpp_class}>>({module_var}, "{class_name}")'
|
'\n py::class_<{cpp_class}, {class_parent}'
|
||||||
'{wrapped_ctors}'
|
'{shared_ptr_type}::shared_ptr<{cpp_class}>>({module_var}, "{class_name}")'
|
||||||
'{wrapped_methods}'
|
'{wrapped_ctors}'
|
||||||
'{wrapped_static_methods}'
|
'{wrapped_methods}'
|
||||||
'{wrapped_properties};\n'.format(
|
'{wrapped_static_methods}'
|
||||||
shared_ptr_type=('boost' if self.use_boost else 'std'),
|
'{wrapped_properties};\n'.format(
|
||||||
cpp_class=cpp_class,
|
shared_ptr_type=('boost' if self.use_boost else 'std'),
|
||||||
class_name=instantiated_class.name,
|
cpp_class=cpp_class,
|
||||||
class_parent=str(instantiated_class.parent_class) +
|
class_name=instantiated_class.name,
|
||||||
(', ' if instantiated_class.parent_class else ''),
|
class_parent=str(instantiated_class.parent_class) +
|
||||||
module_var=module_var,
|
(', ' if instantiated_class.parent_class else ''),
|
||||||
wrapped_ctors=self.wrap_ctors(instantiated_class),
|
module_var=module_var,
|
||||||
wrapped_methods=self.wrap_methods(instantiated_class.methods, cpp_class),
|
wrapped_ctors=self.wrap_ctors(instantiated_class),
|
||||||
wrapped_static_methods=self.wrap_methods(instantiated_class.static_methods, cpp_class),
|
wrapped_methods=self.wrap_methods(instantiated_class.methods,
|
||||||
wrapped_properties=self.wrap_properties(instantiated_class.properties, cpp_class),
|
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):
|
def wrap_stl_class(self, stl_class):
|
||||||
|
"""Wrap STL containers."""
|
||||||
module_var = self._gen_module_var(stl_class.namespaces())
|
module_var = self._gen_module_var(stl_class.namespaces())
|
||||||
cpp_class = stl_class.cpp_class()
|
cpp_class = stl_class.cpp_class()
|
||||||
if cpp_class in self.ignore_classes:
|
if cpp_class in self.ignore_classes:
|
||||||
return ""
|
return ""
|
||||||
|
|
||||||
return ('\n py::class_<{cpp_class}, {class_parent}'
|
return (
|
||||||
'{shared_ptr_type}::shared_ptr<{cpp_class}>>({module_var}, "{class_name}")'
|
'\n py::class_<{cpp_class}, {class_parent}'
|
||||||
'{wrapped_ctors}'
|
'{shared_ptr_type}::shared_ptr<{cpp_class}>>({module_var}, "{class_name}")'
|
||||||
'{wrapped_methods}'
|
'{wrapped_ctors}'
|
||||||
'{wrapped_static_methods}'
|
'{wrapped_methods}'
|
||||||
'{wrapped_properties};\n'.format(
|
'{wrapped_static_methods}'
|
||||||
shared_ptr_type=('boost' if self.use_boost else 'std'),
|
'{wrapped_properties};\n'.format(
|
||||||
cpp_class=cpp_class,
|
shared_ptr_type=('boost' if self.use_boost else 'std'),
|
||||||
class_name=stl_class.name,
|
cpp_class=cpp_class,
|
||||||
class_parent=str(stl_class.parent_class) + (', ' if stl_class.parent_class else ''),
|
class_name=stl_class.name,
|
||||||
module_var=module_var,
|
class_parent=str(stl_class.parent_class) +
|
||||||
wrapped_ctors=self.wrap_ctors(stl_class),
|
(', ' if stl_class.parent_class else ''),
|
||||||
wrapped_methods=self.wrap_methods(stl_class.methods, cpp_class),
|
module_var=module_var,
|
||||||
wrapped_static_methods=self.wrap_methods(stl_class.static_methods, cpp_class),
|
wrapped_ctors=self.wrap_ctors(stl_class),
|
||||||
wrapped_properties=self.wrap_properties(stl_class.properties, cpp_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):
|
def _partial_match(self, namespaces1, namespaces2):
|
||||||
for i in range(min(len(namespaces1), len(namespaces2))):
|
for i in range(min(len(namespaces1), len(namespaces2))):
|
||||||
|
@ -252,6 +276,7 @@ class PybindWrapper(object):
|
||||||
return name
|
return name
|
||||||
|
|
||||||
def wrap_namespace(self, namespace):
|
def wrap_namespace(self, namespace):
|
||||||
|
"""Wrap the complete `namespace`."""
|
||||||
wrapped = ""
|
wrapped = ""
|
||||||
includes = ""
|
includes = ""
|
||||||
|
|
||||||
|
@ -298,7 +323,10 @@ class PybindWrapper(object):
|
||||||
wrapped += self.wrap_instantiated_class(element)
|
wrapped += self.wrap_instantiated_class(element)
|
||||||
|
|
||||||
# Global functions.
|
# 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(
|
wrapped += self.wrap_methods(
|
||||||
all_funcs,
|
all_funcs,
|
||||||
self._add_namespaces('', namespaces)[:-2],
|
self._add_namespaces('', namespaces)[:-2],
|
||||||
|
@ -308,6 +336,7 @@ class PybindWrapper(object):
|
||||||
return wrapped, includes
|
return wrapped, includes
|
||||||
|
|
||||||
def wrap(self):
|
def wrap(self):
|
||||||
|
"""Wrap the code in the interface file."""
|
||||||
wrapped_namespace, includes = self.wrap_namespace(self.module)
|
wrapped_namespace, includes = self.wrap_namespace(self.module)
|
||||||
|
|
||||||
# Export classes for serialization.
|
# 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, )
|
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(
|
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,
|
module_name=self.module_name,
|
||||||
includes=includes,
|
includes=includes,
|
||||||
hoder_type=
|
holder_type=holder_type.format(shared_ptr_type=('boost' if self.use_boost else 'std'))
|
||||||
"PYBIND11_DECLARE_HOLDER_TYPE(TYPE_PLACEHOLDER_DONOTUSE, {shared_ptr_type}::shared_ptr<TYPE_PLACEHOLDER_DONOTUSE>);"
|
if self.use_boost else "",
|
||||||
.format(shared_ptr_type=('boost' if self.use_boost else 'std')) if self.use_boost else "",
|
|
||||||
wrapped_namespace=wrapped_namespace,
|
wrapped_namespace=wrapped_namespace,
|
||||||
boost_class_export=boost_class_export,
|
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
|
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.
|
Instantiate template typename for @p ctype.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
instiated_class (InstantiatedClass):
|
||||||
|
|
||||||
@return If ctype's name is in the @p template_typenames, return the
|
@return If ctype's name is in the @p template_typenames, return the
|
||||||
corresponding type to replace in @p instantiations.
|
corresponding type to replace in @p instantiations.
|
||||||
If ctype name is `This`, return the new typename @p `cpp_typename`.
|
If ctype name is `This`, return the new typename @p `cpp_typename`.
|
||||||
Otherwise, return the original ctype.
|
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)
|
str_arg_typename = str(ctype.typename)
|
||||||
|
|
||||||
if str_arg_typename in template_typenames:
|
if str_arg_typename in template_typenames:
|
||||||
idx = template_typenames.index(str_arg_typename)
|
idx = template_typenames.index(str_arg_typename)
|
||||||
return parser.Type(
|
return parser.Type(
|
||||||
|
@ -20,7 +50,6 @@ def instantiate_type(ctype, template_typenames, instantiations, cpp_typename, in
|
||||||
is_basis=ctype.is_basis,
|
is_basis=ctype.is_basis,
|
||||||
)
|
)
|
||||||
elif str_arg_typename == 'This':
|
elif str_arg_typename == 'This':
|
||||||
# import sys
|
|
||||||
if instantiated_class:
|
if instantiated_class:
|
||||||
name = instantiated_class.original.name
|
name = instantiated_class.original.name
|
||||||
namespaces_name = instantiated_class.namespaces()
|
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
|
# ctype, instantiations, cpp_typename, instantiated_class.instantiations
|
||||||
# ), file=sys.stderr)
|
# ), file=sys.stderr)
|
||||||
cpp_typename = parser.Typename(
|
cpp_typename = parser.Typename(
|
||||||
namespaces_name, instantiations=[inst for inst in instantiated_class.instantiations]
|
namespaces_name,
|
||||||
)
|
instantiations=instantiated_class.instantiations)
|
||||||
return parser.Type(
|
return parser.Type(
|
||||||
typename=cpp_typename,
|
typename=cpp_typename,
|
||||||
is_const=ctype.is_const,
|
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,
|
def instantiate_return_type(return_type, template_typenames, instantiations,
|
||||||
cpp_typename, instantiated_class=None):
|
cpp_typename, instantiated_class=None):
|
||||||
new_type1 = instantiate_type(
|
"""Instantiate the return type."""
|
||||||
return_type.type1, template_typenames, instantiations, cpp_typename, instantiated_class=instantiated_class)
|
new_type1 = instantiate_type(return_type.type1,
|
||||||
|
template_typenames,
|
||||||
|
instantiations,
|
||||||
|
cpp_typename,
|
||||||
|
instantiated_class=instantiated_class)
|
||||||
if return_type.type2:
|
if return_type.type2:
|
||||||
new_type2 = instantiate_type(
|
new_type2 = instantiate_type(return_type.type2,
|
||||||
return_type.type2, template_typenames, instantiations,
|
template_typenames,
|
||||||
cpp_typename, instantiated_class=instantiated_class)
|
instantiations,
|
||||||
|
cpp_typename,
|
||||||
|
instantiated_class=instantiated_class)
|
||||||
else:
|
else:
|
||||||
new_type2 = ''
|
new_type2 = ''
|
||||||
return parser.ReturnType(new_type1, new_type2)
|
return parser.ReturnType(new_type1, new_type2)
|
||||||
|
@ -91,7 +126,7 @@ def instantiate_name(original_name, instantiations):
|
||||||
inst_name = ''
|
inst_name = ''
|
||||||
|
|
||||||
return "{}{}".format(original_name, "".join(
|
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):
|
class InstantiatedMethod(parser.Method):
|
||||||
|
@ -111,6 +146,7 @@ class InstantiatedMethod(parser.Method):
|
||||||
self.return_type = original.return_type
|
self.return_type = original.return_type
|
||||||
self.args = original.args
|
self.args = original.args
|
||||||
else:
|
else:
|
||||||
|
#TODO(Varun) enable multiple templates for methods
|
||||||
if len(self.original.template.typenames) > 1:
|
if len(self.original.template.typenames) > 1:
|
||||||
raise ValueError("Can only instantiate template method with "
|
raise ValueError("Can only instantiate template method with "
|
||||||
"single template parameter.")
|
"single template parameter.")
|
||||||
|
@ -133,11 +169,20 @@ class InstantiatedMethod(parser.Method):
|
||||||
)
|
)
|
||||||
self.args = parser.ArgumentList(instantiated_args)
|
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):
|
def to_cpp(self):
|
||||||
|
"""Generate the C++ code for wrapping."""
|
||||||
if self.original.template:
|
if self.original.template:
|
||||||
return "{}<{}>".format(self.original.name, self.instantiation)
|
ret = "{}<{}>".format(self.original.name, self.instantiation)
|
||||||
else:
|
else:
|
||||||
return self.original.name
|
ret = self.original.name
|
||||||
|
return ret
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return "Instantiated {}".format(
|
return "Instantiated {}".format(
|
||||||
|
@ -146,7 +191,10 @@ class InstantiatedMethod(parser.Method):
|
||||||
|
|
||||||
|
|
||||||
class InstantiatedClass(parser.Class):
|
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>
|
Template <T, U>
|
||||||
Instantiations: [T1, U1]
|
Instantiations: [T1, U1]
|
||||||
|
@ -190,6 +238,18 @@ class InstantiatedClass(parser.Class):
|
||||||
for inst in method.template.instantiations[0]:
|
for inst in method.template.instantiations[0]:
|
||||||
self.methods.append(InstantiatedMethod(method, inst))
|
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):
|
def __repr__(self):
|
||||||
return "{virtual} class {name} [{cpp_class}]: {parent_class}\n"\
|
return "{virtual} class {name} [{cpp_class}]: {parent_class}\n"\
|
||||||
"{ctors}\n{static_methods}\n{methods}".format(
|
"{ctors}\n{static_methods}\n{methods}".format(
|
||||||
|
@ -204,6 +264,7 @@ class InstantiatedClass(parser.Class):
|
||||||
)
|
)
|
||||||
|
|
||||||
def instantiate_ctors(self):
|
def instantiate_ctors(self):
|
||||||
|
"""Instantiate the class constructors."""
|
||||||
instantiated_ctors = []
|
instantiated_ctors = []
|
||||||
for ctor in self.original.ctors:
|
for ctor in self.original.ctors:
|
||||||
instantiated_args = instantiate_args_list(
|
instantiated_args = instantiate_args_list(
|
||||||
|
@ -220,6 +281,7 @@ class InstantiatedClass(parser.Class):
|
||||||
return instantiated_ctors
|
return instantiated_ctors
|
||||||
|
|
||||||
def instantiate_static_methods(self):
|
def instantiate_static_methods(self):
|
||||||
|
"""Instantiate static methods in the class."""
|
||||||
instantiated_static_methods = []
|
instantiated_static_methods = []
|
||||||
for static_method in self.original.static_methods:
|
for static_method in self.original.static_methods:
|
||||||
instantiated_args = instantiate_args_list(
|
instantiated_args = instantiate_args_list(
|
||||||
|
@ -274,6 +336,7 @@ class InstantiatedClass(parser.Class):
|
||||||
return class_instantiated_methods
|
return class_instantiated_methods
|
||||||
|
|
||||||
def instantiate_properties(self):
|
def instantiate_properties(self):
|
||||||
|
"""Instantiate the class properties."""
|
||||||
instantiated_properties = instantiate_args_list(
|
instantiated_properties = instantiate_args_list(
|
||||||
self.original.properties,
|
self.original.properties,
|
||||||
self.original.template.typenames,
|
self.original.template.typenames,
|
||||||
|
@ -283,6 +346,7 @@ class InstantiatedClass(parser.Class):
|
||||||
return instantiated_properties
|
return instantiated_properties
|
||||||
|
|
||||||
def cpp_class(self):
|
def cpp_class(self):
|
||||||
|
"""Generate the C++ code for wrapping."""
|
||||||
return self.cpp_typename().to_cpp()
|
return self.cpp_typename().to_cpp()
|
||||||
|
|
||||||
def cpp_typename(self):
|
def cpp_typename(self):
|
||||||
|
@ -303,7 +367,10 @@ class InstantiatedClass(parser.Class):
|
||||||
|
|
||||||
def instantiate_namespace_inplace(namespace):
|
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.
|
the instantiated content.
|
||||||
"""
|
"""
|
||||||
instantiated_content = []
|
instantiated_content = []
|
||||||
|
@ -316,15 +383,14 @@ def instantiate_namespace_inplace(namespace):
|
||||||
instantiated_content.append(
|
instantiated_content.append(
|
||||||
InstantiatedClass(original_class, []))
|
InstantiatedClass(original_class, []))
|
||||||
else:
|
else:
|
||||||
if (len(original_class.template.typenames) > 1
|
# Use itertools to get all possible combinations of instantiations
|
||||||
and original_class.template.instantiations[0]):
|
# Works even if one template does not have an instantiation list
|
||||||
raise ValueError(
|
for instantiations in itertools.product(
|
||||||
"Can't instantiate multi-parameter templates here. "
|
*original_class.template.instantiations):
|
||||||
"Please use typedef template instantiation."
|
|
||||||
)
|
|
||||||
for inst in original_class.template.instantiations[0]:
|
|
||||||
instantiated_content.append(
|
instantiated_content.append(
|
||||||
InstantiatedClass(original_class, [inst]))
|
InstantiatedClass(original_class,
|
||||||
|
list(instantiations)))
|
||||||
|
|
||||||
elif isinstance(element, parser.TypedefTemplateInstantiation):
|
elif isinstance(element, parser.TypedefTemplateInstantiation):
|
||||||
typedef_inst = element
|
typedef_inst = element
|
||||||
original_class = namespace.top_level().find_class(
|
original_class = namespace.top_level().find_class(
|
||||||
|
|
|
@ -11,7 +11,7 @@
|
||||||
|
|
||||||
{boost_class_export}
|
{boost_class_export}
|
||||||
|
|
||||||
{hoder_type}
|
{holder_type}
|
||||||
|
|
||||||
#include "python/preamble.h"
|
#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.
|
and invoked during the wrapping by CMake.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
# pylint: disable=import-error
|
||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
|
|
||||||
import gtwrap.interface_parser as parser
|
import gtwrap.interface_parser as parser
|
||||||
|
@ -68,13 +70,16 @@ def main():
|
||||||
if top_module_namespaces[0]:
|
if top_module_namespaces[0]:
|
||||||
top_module_namespaces = [''] + top_module_namespaces
|
top_module_namespaces = [''] + top_module_namespaces
|
||||||
|
|
||||||
|
# Read in the complete interface (.i) file
|
||||||
with open(args.src, "r") as f:
|
with open(args.src, "r") as f:
|
||||||
content = f.read()
|
content = f.read()
|
||||||
|
|
||||||
module = parser.Module.parseString(content)
|
module = parser.Module.parseString(content)
|
||||||
instantiator.instantiate_namespace_inplace(module)
|
instantiator.instantiate_namespace_inplace(module)
|
||||||
|
|
||||||
with open(args.template, "r") as f:
|
with open(args.template, "r") as f:
|
||||||
template_content = f.read()
|
template_content = f.read()
|
||||||
|
|
||||||
wrapper = PybindWrapper(
|
wrapper = PybindWrapper(
|
||||||
module=module,
|
module=module,
|
||||||
module_name=args.module_name,
|
module_name=args.module_name,
|
||||||
|
@ -84,7 +89,10 @@ def main():
|
||||||
module_template=template_content,
|
module_template=template_content,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# Wrap the code and get back the cpp/cc code.
|
||||||
cc_content = wrapper.wrap()
|
cc_content = wrapper.wrap()
|
||||||
|
|
||||||
|
# Generate the C++ code which Pybind11 will use.
|
||||||
with open(args.out, "w") as f:
|
with open(args.out, "w") as f:
|
||||||
f.write(cc_content)
|
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)
|
function obj = MyFactorPosePoint2(varargin)
|
||||||
if nargin == 2 && isa(varargin{1}, 'uint64') && varargin{1} == uint64(5139824614673773682)
|
if nargin == 2 && isa(varargin{1}, 'uint64') && varargin{1} == uint64(5139824614673773682)
|
||||||
my_ptr = varargin{2};
|
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')
|
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
|
else
|
||||||
error('Arguments do not match any overload of MyFactorPosePoint2 constructor');
|
error('Arguments do not match any overload of MyFactorPosePoint2 constructor');
|
||||||
end
|
end
|
||||||
|
@ -22,7 +22,7 @@ classdef MyFactorPosePoint2 < handle
|
||||||
end
|
end
|
||||||
|
|
||||||
function delete(obj)
|
function delete(obj)
|
||||||
geometry_wrapper(91, obj.ptr_MyFactorPosePoint2);
|
geometry_wrapper(95, obj.ptr_MyFactorPosePoint2);
|
||||||
end
|
end
|
||||||
|
|
||||||
function display(obj), obj.print(''); end
|
function display(obj), obj.print(''); end
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
function varargout = aGlobalFunction(varargin)
|
function varargout = aGlobalFunction(varargin)
|
||||||
if length(varargin) == 0
|
if length(varargin) == 0
|
||||||
varargout{1} = geometry_wrapper(95, varargin{:});
|
varargout{1} = geometry_wrapper(99, varargin{:});
|
||||||
else
|
else
|
||||||
error('Arguments do not match any overload of function aGlobalFunction');
|
error('Arguments do not match any overload of function aGlobalFunction');
|
||||||
end
|
end
|
||||||
|
|
|
@ -11,9 +11,11 @@
|
||||||
|
|
||||||
typedef MyTemplate<gtsam::Point2> MyTemplatePoint2;
|
typedef MyTemplate<gtsam::Point2> MyTemplatePoint2;
|
||||||
typedef MyTemplate<gtsam::Matrix> MyTemplateMatrix;
|
typedef MyTemplate<gtsam::Matrix> MyTemplateMatrix;
|
||||||
typedef PrimitiveRef<double> PrimitiveRefdouble;
|
typedef PrimitiveRef<double> PrimitiveRefDouble;
|
||||||
typedef MyVector<3> MyVector3;
|
typedef MyVector<3> MyVector3;
|
||||||
typedef MyVector<12> MyVector12;
|
typedef MyVector<12> MyVector12;
|
||||||
|
typedef MultipleTemplates<int, double> MultipleTemplatesIntDouble;
|
||||||
|
typedef MultipleTemplates<int, float> MultipleTemplatesIntFloat;
|
||||||
typedef MyFactor<gtsam::Pose2, gtsam::Matrix> MyFactorPosePoint2;
|
typedef MyFactor<gtsam::Pose2, gtsam::Matrix> MyFactorPosePoint2;
|
||||||
|
|
||||||
BOOST_CLASS_EXPORT_GUID(gtsam::Point2, "gtsamPoint2");
|
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;
|
static Collector_MyTemplatePoint2 collector_MyTemplatePoint2;
|
||||||
typedef std::set<boost::shared_ptr<MyTemplateMatrix>*> Collector_MyTemplateMatrix;
|
typedef std::set<boost::shared_ptr<MyTemplateMatrix>*> Collector_MyTemplateMatrix;
|
||||||
static Collector_MyTemplateMatrix collector_MyTemplateMatrix;
|
static Collector_MyTemplateMatrix collector_MyTemplateMatrix;
|
||||||
typedef std::set<boost::shared_ptr<PrimitiveRefdouble>*> Collector_PrimitiveRefdouble;
|
typedef std::set<boost::shared_ptr<PrimitiveRefDouble>*> Collector_PrimitiveRefDouble;
|
||||||
static Collector_PrimitiveRefdouble collector_PrimitiveRefdouble;
|
static Collector_PrimitiveRefDouble collector_PrimitiveRefDouble;
|
||||||
typedef std::set<boost::shared_ptr<MyVector3>*> Collector_MyVector3;
|
typedef std::set<boost::shared_ptr<MyVector3>*> Collector_MyVector3;
|
||||||
static Collector_MyVector3 collector_MyVector3;
|
static Collector_MyVector3 collector_MyVector3;
|
||||||
typedef std::set<boost::shared_ptr<MyVector12>*> Collector_MyVector12;
|
typedef std::set<boost::shared_ptr<MyVector12>*> Collector_MyVector12;
|
||||||
static Collector_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;
|
typedef std::set<boost::shared_ptr<MyFactorPosePoint2>*> Collector_MyFactorPosePoint2;
|
||||||
static Collector_MyFactorPosePoint2 collector_MyFactorPosePoint2;
|
static Collector_MyFactorPosePoint2 collector_MyFactorPosePoint2;
|
||||||
|
|
||||||
|
@ -82,10 +88,10 @@ void _deleteAllObjects()
|
||||||
collector_MyTemplateMatrix.erase(iter++);
|
collector_MyTemplateMatrix.erase(iter++);
|
||||||
anyDeleted = true;
|
anyDeleted = true;
|
||||||
} }
|
} }
|
||||||
{ for(Collector_PrimitiveRefdouble::iterator iter = collector_PrimitiveRefdouble.begin();
|
{ for(Collector_PrimitiveRefDouble::iterator iter = collector_PrimitiveRefDouble.begin();
|
||||||
iter != collector_PrimitiveRefdouble.end(); ) {
|
iter != collector_PrimitiveRefDouble.end(); ) {
|
||||||
delete *iter;
|
delete *iter;
|
||||||
collector_PrimitiveRefdouble.erase(iter++);
|
collector_PrimitiveRefDouble.erase(iter++);
|
||||||
anyDeleted = true;
|
anyDeleted = true;
|
||||||
} }
|
} }
|
||||||
{ for(Collector_MyVector3::iterator iter = collector_MyVector3.begin();
|
{ for(Collector_MyVector3::iterator iter = collector_MyVector3.begin();
|
||||||
|
@ -100,6 +106,18 @@ void _deleteAllObjects()
|
||||||
collector_MyVector12.erase(iter++);
|
collector_MyVector12.erase(iter++);
|
||||||
anyDeleted = true;
|
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();
|
{ for(Collector_MyFactorPosePoint2::iterator iter = collector_MyFactorPosePoint2.begin();
|
||||||
iter != collector_MyFactorPosePoint2.end(); ) {
|
iter != collector_MyFactorPosePoint2.end(); ) {
|
||||||
delete *iter;
|
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);
|
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);
|
mexAtExit(&_deleteAllObjects);
|
||||||
typedef boost::shared_ptr<PrimitiveRef<double>> Shared;
|
typedef boost::shared_ptr<PrimitiveRef<double>> Shared;
|
||||||
|
|
||||||
Shared *self = *reinterpret_cast<Shared**> (mxGetData(in[0]));
|
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);
|
mexAtExit(&_deleteAllObjects);
|
||||||
typedef boost::shared_ptr<PrimitiveRef<double>> Shared;
|
typedef boost::shared_ptr<PrimitiveRef<double>> Shared;
|
||||||
|
|
||||||
Shared *self = new Shared(new PrimitiveRef<double>());
|
Shared *self = new Shared(new PrimitiveRef<double>());
|
||||||
collector_PrimitiveRefdouble.insert(self);
|
collector_PrimitiveRefDouble.insert(self);
|
||||||
out[0] = mxCreateNumericMatrix(1, 1, mxUINT32OR64_CLASS, mxREAL);
|
out[0] = mxCreateNumericMatrix(1, 1, mxUINT32OR64_CLASS, mxREAL);
|
||||||
*reinterpret_cast<Shared**> (mxGetData(out[0])) = self;
|
*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;
|
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]));
|
Shared *self = *reinterpret_cast<Shared**>(mxGetData(in[0]));
|
||||||
Collector_PrimitiveRefdouble::iterator item;
|
Collector_PrimitiveRefDouble::iterator item;
|
||||||
item = collector_PrimitiveRefdouble.find(self);
|
item = collector_PrimitiveRefDouble.find(self);
|
||||||
if(item != collector_PrimitiveRefdouble.end()) {
|
if(item != collector_PrimitiveRefDouble.end()) {
|
||||||
delete self;
|
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]);
|
double t = unwrap< double >(in[0]);
|
||||||
out[0] = wrap_shared_ptr(boost::make_shared<PrimitiveRef<double>>(PrimitiveRef<double>::Brutal(t)),"PrimitiveRefdouble", false);
|
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);
|
mexAtExit(&_deleteAllObjects);
|
||||||
typedef boost::shared_ptr<MyFactor<gtsam::Pose2, gtsam::Matrix>> Shared;
|
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);
|
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);
|
mexAtExit(&_deleteAllObjects);
|
||||||
typedef boost::shared_ptr<MyFactor<gtsam::Pose2, gtsam::Matrix>> Shared;
|
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;
|
*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;
|
typedef boost::shared_ptr<MyFactor<gtsam::Pose2, gtsam::Matrix>> Shared;
|
||||||
checkArguments("delete_MyFactorPosePoint2",nargout,nargin,1);
|
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);
|
checkArguments("load2D",nargout,nargin,5);
|
||||||
string filename = unwrap< string >(in[0]);
|
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[0] = wrap_shared_ptr(pairResult.first,"gtsam.NonlinearFactorGraph", false);
|
||||||
out[1] = wrap_shared_ptr(pairResult.second,"gtsam.Values", 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);
|
checkArguments("load2D",nargout,nargin,5);
|
||||||
string filename = unwrap< string >(in[0]);
|
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[0] = wrap_shared_ptr(pairResult.first,"gtsam.NonlinearFactorGraph", false);
|
||||||
out[1] = wrap_shared_ptr(pairResult.second,"gtsam.Values", 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);
|
checkArguments("load2D",nargout,nargin,2);
|
||||||
string filename = unwrap< string >(in[0]);
|
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[0] = wrap_shared_ptr(pairResult.first,"gtsam.NonlinearFactorGraph", false);
|
||||||
out[1] = wrap_shared_ptr(pairResult.second,"gtsam.Values", 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);
|
checkArguments("aGlobalFunction",nargout,nargin,0);
|
||||||
out[0] = wrap< Vector >(aGlobalFunction());
|
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);
|
checkArguments("overloadedGlobalFunction",nargout,nargin,1);
|
||||||
int a = unwrap< int >(in[0]);
|
int a = unwrap< int >(in[0]);
|
||||||
out[0] = wrap< Vector >(overloadedGlobalFunction(a));
|
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);
|
checkArguments("overloadedGlobalFunction",nargout,nargin,2);
|
||||||
int a = unwrap< int >(in[0]);
|
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);
|
MyTemplateMatrix_Level_78(nargout, out, nargin-1, in+1);
|
||||||
break;
|
break;
|
||||||
case 79:
|
case 79:
|
||||||
PrimitiveRefdouble_collectorInsertAndMakeBase_79(nargout, out, nargin-1, in+1);
|
PrimitiveRefDouble_collectorInsertAndMakeBase_79(nargout, out, nargin-1, in+1);
|
||||||
break;
|
break;
|
||||||
case 80:
|
case 80:
|
||||||
PrimitiveRefdouble_constructor_80(nargout, out, nargin-1, in+1);
|
PrimitiveRefDouble_constructor_80(nargout, out, nargin-1, in+1);
|
||||||
break;
|
break;
|
||||||
case 81:
|
case 81:
|
||||||
PrimitiveRefdouble_deconstructor_81(nargout, out, nargin-1, in+1);
|
PrimitiveRefDouble_deconstructor_81(nargout, out, nargin-1, in+1);
|
||||||
break;
|
break;
|
||||||
case 82:
|
case 82:
|
||||||
PrimitiveRefdouble_Brutal_82(nargout, out, nargin-1, in+1);
|
PrimitiveRefDouble_Brutal_82(nargout, out, nargin-1, in+1);
|
||||||
break;
|
break;
|
||||||
case 83:
|
case 83:
|
||||||
MyVector3_collectorInsertAndMakeBase_83(nargout, out, nargin-1, in+1);
|
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);
|
MyVector12_deconstructor_88(nargout, out, nargin-1, in+1);
|
||||||
break;
|
break;
|
||||||
case 89:
|
case 89:
|
||||||
MyFactorPosePoint2_collectorInsertAndMakeBase_89(nargout, out, nargin-1, in+1);
|
MultipleTemplatesIntDouble_collectorInsertAndMakeBase_89(nargout, out, nargin-1, in+1);
|
||||||
break;
|
break;
|
||||||
case 90:
|
case 90:
|
||||||
MyFactorPosePoint2_constructor_90(nargout, out, nargin-1, in+1);
|
MultipleTemplatesIntDouble_deconstructor_90(nargout, out, nargin-1, in+1);
|
||||||
break;
|
break;
|
||||||
case 91:
|
case 91:
|
||||||
MyFactorPosePoint2_deconstructor_91(nargout, out, nargin-1, in+1);
|
MultipleTemplatesIntFloat_collectorInsertAndMakeBase_91(nargout, out, nargin-1, in+1);
|
||||||
break;
|
break;
|
||||||
case 92:
|
case 92:
|
||||||
load2D_92(nargout, out, nargin-1, in+1);
|
MultipleTemplatesIntFloat_deconstructor_92(nargout, out, nargin-1, in+1);
|
||||||
break;
|
break;
|
||||||
case 93:
|
case 93:
|
||||||
load2D_93(nargout, out, nargin-1, in+1);
|
MyFactorPosePoint2_collectorInsertAndMakeBase_93(nargout, out, nargin-1, in+1);
|
||||||
break;
|
break;
|
||||||
case 94:
|
case 94:
|
||||||
load2D_94(nargout, out, nargin-1, in+1);
|
MyFactorPosePoint2_constructor_94(nargout, out, nargin-1, in+1);
|
||||||
break;
|
break;
|
||||||
case 95:
|
case 95:
|
||||||
aGlobalFunction_95(nargout, out, nargin-1, in+1);
|
MyFactorPosePoint2_deconstructor_95(nargout, out, nargin-1, in+1);
|
||||||
break;
|
break;
|
||||||
case 96:
|
case 96:
|
||||||
overloadedGlobalFunction_96(nargout, out, nargin-1, in+1);
|
load2D_96(nargout, out, nargin-1, in+1);
|
||||||
break;
|
break;
|
||||||
case 97:
|
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;
|
break;
|
||||||
}
|
}
|
||||||
} catch(const std::exception& e) {
|
} catch(const std::exception& e) {
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
function varargout = load2D(varargin)
|
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')
|
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')
|
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')
|
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
|
else
|
||||||
error('Arguments do not match any overload of function load2D');
|
error('Arguments do not match any overload of function load2D');
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
function varargout = overloadedGlobalFunction(varargin)
|
function varargout = overloadedGlobalFunction(varargin)
|
||||||
if length(varargin) == 1 && isa(varargin{1},'numeric')
|
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')
|
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
|
else
|
||||||
error('Arguments do not match any overload of function overloadedGlobalFunction');
|
error('Arguments do not match any overload of function overloadedGlobalFunction');
|
||||||
end
|
end
|
||||||
|
|
|
@ -115,7 +115,8 @@ PYBIND11_MODULE(geometry_py, m_) {
|
||||||
gtsam::RedirectCout redirect;
|
gtsam::RedirectCout redirect;
|
||||||
a.print();
|
a.print();
|
||||||
return redirect.str();
|
return redirect.str();
|
||||||
});
|
})
|
||||||
|
.def_readwrite("model_ptr", &Test::model_ptr);
|
||||||
|
|
||||||
py::class_<MyBase, std::shared_ptr<MyBase>>(m_, "MyBase");
|
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("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"));
|
.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(py::init<>())
|
||||||
.def_static("Brutal",[](const double& t){return PrimitiveRef<double>::Brutal(t);}, py::arg("t"));
|
.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")
|
py::class_<MyVector<12>, std::shared_ptr<MyVector<12>>>(m_, "MyVector12")
|
||||||
.def(py::init<>());
|
.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")
|
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"));
|
.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
|
// another comment
|
||||||
Test();
|
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, Matrix A) const; // intentionally the first method
|
||||||
pair<Vector,Matrix> return_pair (Vector v) const; // overload
|
pair<Vector,Matrix> return_pair (Vector v) const; // overload
|
||||||
|
|
||||||
|
@ -160,3 +163,7 @@ class MyVector {
|
||||||
// comments at the end!
|
// comments at the end!
|
||||||
|
|
||||||
// even more 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}
|
{boost_class_export}
|
||||||
|
|
||||||
{hoder_type}
|
{holder_type}
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
|
|
|
@ -1,21 +1,26 @@
|
||||||
"""
|
"""
|
||||||
Unit test for Matlab wrap program
|
Unit tests for Matlab wrap program
|
||||||
Author: Matthew Sklar
|
Author: Matthew Sklar, Varun Agrawal
|
||||||
Date: March 2019
|
Date: March 2019
|
||||||
"""
|
"""
|
||||||
|
# pylint: disable=import-error, wrong-import-position, too-many-branches
|
||||||
|
|
||||||
|
import filecmp
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
import unittest
|
import unittest
|
||||||
import filecmp
|
|
||||||
|
|
||||||
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
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.interface_parser as parser
|
||||||
|
import gtwrap.template_instantiator as instantiator
|
||||||
from gtwrap.matlab_wrapper import MatlabWrapper
|
from gtwrap.matlab_wrapper import MatlabWrapper
|
||||||
|
|
||||||
|
|
||||||
class TestWrap(unittest.TestCase):
|
class TestWrap(unittest.TestCase):
|
||||||
|
"""
|
||||||
|
Test the Matlab wrapper
|
||||||
|
"""
|
||||||
TEST_DIR = os.path.dirname(os.path.realpath(__file__)) + "/"
|
TEST_DIR = os.path.dirname(os.path.realpath(__file__)) + "/"
|
||||||
MATLAB_TEST_DIR = TEST_DIR + "expected-matlab/"
|
MATLAB_TEST_DIR = TEST_DIR + "expected-matlab/"
|
||||||
MATLAB_ACTUAL_DIR = TEST_DIR + "actual-matlab/"
|
MATLAB_ACTUAL_DIR = TEST_DIR + "actual-matlab/"
|
||||||
|
@ -31,11 +36,11 @@ class TestWrap(unittest.TestCase):
|
||||||
"""
|
"""
|
||||||
if path == '':
|
if path == '':
|
||||||
path = self.MATLAB_ACTUAL_DIR
|
path = self.MATLAB_ACTUAL_DIR
|
||||||
|
|
||||||
for c in cc_content:
|
for c in cc_content:
|
||||||
if type(c) == list:
|
if isinstance(c, list):
|
||||||
if len(c) == 0:
|
if len(c) == 0:
|
||||||
continue
|
continue
|
||||||
import sys
|
|
||||||
print("c object: {}".format(c[0][0]), file=sys.stderr)
|
print("c object: {}".format(c[0][0]), file=sys.stderr)
|
||||||
path_to_folder = path + '/' + c[0][0]
|
path_to_folder = path + '/' + c[0][0]
|
||||||
|
|
||||||
|
@ -46,13 +51,12 @@ class TestWrap(unittest.TestCase):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
for sub_content in c:
|
for sub_content in c:
|
||||||
import sys
|
|
||||||
print("sub object: {}".format(sub_content[1][0][0]), file=sys.stderr)
|
print("sub object: {}".format(sub_content[1][0][0]), file=sys.stderr)
|
||||||
self.generate_content(sub_content[1], path_to_folder)
|
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]
|
path_to_folder = path + '/' + c[0]
|
||||||
|
|
||||||
import sys
|
|
||||||
print("[generate_content_global]: {}".format(path_to_folder), file=sys.stderr)
|
print("[generate_content_global]: {}".format(path_to_folder), file=sys.stderr)
|
||||||
if not os.path.isdir(path_to_folder):
|
if not os.path.isdir(path_to_folder):
|
||||||
try:
|
try:
|
||||||
|
@ -60,15 +64,14 @@ class TestWrap(unittest.TestCase):
|
||||||
except OSError:
|
except OSError:
|
||||||
pass
|
pass
|
||||||
for sub_content in c[1]:
|
for sub_content in c[1]:
|
||||||
import sys
|
|
||||||
path_to_file = path_to_folder + '/' + sub_content[0]
|
path_to_file = path_to_folder + '/' + sub_content[0]
|
||||||
print("[generate_global_method]: {}".format(path_to_file), file=sys.stderr)
|
print("[generate_global_method]: {}".format(path_to_file), file=sys.stderr)
|
||||||
with open(path_to_file, 'w') as f:
|
with open(path_to_file, 'w') as f:
|
||||||
f.write(sub_content[1])
|
f.write(sub_content[1])
|
||||||
|
|
||||||
else:
|
else:
|
||||||
path_to_file = path + '/' + c[0]
|
path_to_file = path + '/' + c[0]
|
||||||
|
|
||||||
import sys
|
|
||||||
print("[generate_content]: {}".format(path_to_file), file=sys.stderr)
|
print("[generate_content]: {}".format(path_to_file), file=sys.stderr)
|
||||||
if not os.path.isdir(path_to_file):
|
if not os.path.isdir(path_to_file):
|
||||||
try:
|
try:
|
||||||
|
@ -80,7 +83,8 @@ class TestWrap(unittest.TestCase):
|
||||||
f.write(c[1])
|
f.write(c[1])
|
||||||
|
|
||||||
def test_geometry_matlab(self):
|
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
|
python3 wrap/matlab_wrapper.py --src wrap/tests/geometry.h
|
||||||
--module_name geometry --out wrap/tests/actual-matlab
|
--module_name geometry --out wrap/tests/actual-matlab
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -1,27 +1,29 @@
|
||||||
"""
|
"""
|
||||||
Unit test for Pybind wrap program
|
Unit test for Pybind wrap program
|
||||||
Author: Matthew Sklar
|
Author: Matthew Sklar, Varun Agrawal
|
||||||
Date: February 2019
|
Date: February 2019
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
# pylint: disable=import-error, wrong-import-position, too-many-branches
|
||||||
|
|
||||||
|
import filecmp
|
||||||
import os
|
import os
|
||||||
|
import os.path as path
|
||||||
import sys
|
import sys
|
||||||
import unittest
|
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.dirname(os.path.dirname(os.path.abspath(__file__))))
|
||||||
sys.path.append(os.path.normpath(os.path.abspath(os.path.join(__file__, '../../../build/wrap'))))
|
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.interface_parser as parser
|
||||||
import gtwrap.template_instantiator as instantiator
|
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__))))
|
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
||||||
|
|
||||||
|
|
||||||
class TestWrap(unittest.TestCase):
|
class TestWrap(unittest.TestCase):
|
||||||
|
"""Tests for Python wrapper based on Pybind11."""
|
||||||
TEST_DIR = os.path.dirname(os.path.realpath(__file__)) + "/"
|
TEST_DIR = os.path.dirname(os.path.realpath(__file__)) + "/"
|
||||||
|
|
||||||
def test_geometry_python(self):
|
def test_geometry_python(self):
|
||||||
|
@ -39,7 +41,7 @@ class TestWrap(unittest.TestCase):
|
||||||
|
|
||||||
with open(self.TEST_DIR + "pybind_wrapper.tpl") as template_file:
|
with open(self.TEST_DIR + "pybind_wrapper.tpl") as template_file:
|
||||||
module_template = template_file.read()
|
module_template = template_file.read()
|
||||||
|
|
||||||
# Create Pybind wrapper instance
|
# Create Pybind wrapper instance
|
||||||
wrapper = PybindWrapper(
|
wrapper = PybindWrapper(
|
||||||
module=module,
|
module=module,
|
||||||
|
|
Loading…
Reference in New Issue