diff --git a/CMakeLists.txt b/CMakeLists.txt index 5e2b24f..035427b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -37,7 +37,7 @@ configure_package_config_file( INSTALL_INCLUDE_DIR) # Set all the install paths -set(GTWRAP_CMAKE_INSTALL_DIR $${INSTALL_CMAKE_DIR}) +set(GTWRAP_CMAKE_INSTALL_DIR ${INSTALL_CMAKE_DIR}) set(GTWRAP_LIB_INSTALL_DIR ${INSTALL_LIB_DIR}) set(GTWRAP_BIN_INSTALL_DIR ${INSTALL_BIN_DIR}) set(GTWRAP_INCLUDE_INSTALL_DIR ${INSTALL_INCLUDE_DIR}) diff --git a/gtwrap/interface_parser/enum.py b/gtwrap/interface_parser/enum.py index 265e1ad..8f875a5 100644 --- a/gtwrap/interface_parser/enum.py +++ b/gtwrap/interface_parser/enum.py @@ -62,9 +62,7 @@ def cpp_typename(self): Return a Typename with the namespaces and cpp name of this class. """ - namespaces_name = self.namespaces() - namespaces_name.append(self.name) - return Typename(namespaces_name) + return Typename(self.name, self.namespaces()) def __repr__(self): return "Enum: {0}".format(self.name) diff --git a/gtwrap/interface_parser/function.py b/gtwrap/interface_parser/function.py index 76ad961..b8a97e8 100644 --- a/gtwrap/interface_parser/function.py +++ b/gtwrap/interface_parser/function.py @@ -12,8 +12,7 @@ from typing import Any, Iterable, List, Union -from pyparsing import (Literal, Optional, ParseResults, # type: ignore - delimitedList) +from pyparsing import Literal, Optional, ParseResults, delimitedList from .template import Template from .tokens import (COMMA, DEFAULT_ARG, EQUAL, IDENT, LOPBRACK, LPAREN, PAIR, diff --git a/gtwrap/interface_parser/type.py b/gtwrap/interface_parser/type.py index 6d2a2b8..5303973 100644 --- a/gtwrap/interface_parser/type.py +++ b/gtwrap/interface_parser/type.py @@ -42,13 +42,14 @@ class Typename: namespaces_name_rule = delimitedList(IDENT, "::") rule = ( namespaces_name_rule("namespaces_and_name") # - ).setParseAction(lambda t: Typename(t)) + ).setParseAction(lambda t: Typename.from_parse_result(t)) def __init__(self, - t: ParseResults, + name: str, + namespaces: list[str], instantiations: Sequence[ParseResults] = ()): - self.name = t[-1] # the name is the last element in this list - self.namespaces = t[:-1] + self.name = name + self.namespaces = namespaces # If the first namespace is empty string, just get rid of it. if self.namespaces and self.namespaces[0] == '': @@ -63,12 +64,38 @@ def __init__(self, self.instantiations = [] @staticmethod - def from_parse_result(parse_result: Union[str, list]): + def from_parse_result(parse_result: list): """Unpack the parsed result to get the Typename instance.""" - return parse_result[0] + name = parse_result[-1] # the name is the last element in this list + namespaces = parse_result[:-1] + return Typename(name, namespaces) def __repr__(self) -> str: - return self.to_cpp() + if self.get_template_args(): + templates = f"<{self.get_template_args()}>" + else: + templates = "" + + if len(self.namespaces) > 0: + namespaces = "::".join(self.namespaces) + "::" + else: + namespaces = "" + + return f"{namespaces}{self.name}{templates}" + + def get_template_args(self) -> str: + """Return the template args as a string, e.g. .""" + return ", ".join([inst.to_cpp() for inst in self.instantiations]) + + def templated_name(self) -> str: + """Return the name without namespace and with the template instantiations if any.""" + if self.instantiations: + templates = self.get_template_args() + name = f"{self.name}<{templates}>" + else: + name = self.name + + return name def instantiated_name(self) -> str: """Get the instantiated name of the type.""" @@ -84,8 +111,7 @@ def qualified_name(self): def to_cpp(self) -> str: """Generate the C++ code for wrapping.""" if self.instantiations: - cpp_name = self.name + "<{}>".format(", ".join( - [inst.to_cpp() for inst in self.instantiations])) + cpp_name = self.name + f"<{self.get_template_args()}>" else: cpp_name = self.name return '{}{}{}'.format( @@ -129,7 +155,7 @@ class BasicType: rule = (Or(BASIC_TYPES)("typename")).setParseAction(lambda t: BasicType(t)) def __init__(self, t: ParseResults): - self.typename = Typename(t) + self.typename = Typename.from_parse_result(t) class CustomType: @@ -148,7 +174,7 @@ class CustomType: rule = (Typename.rule("typename")).setParseAction(lambda t: CustomType(t)) def __init__(self, t: ParseResults): - self.typename = Typename(t) + self.typename = Typename.from_parse_result(t) class Type: @@ -226,18 +252,16 @@ def to_cpp(self) -> str: """ if self.is_shared_ptr: - typename = "std::shared_ptr<{typename}>".format( - typename=self.get_typename()) + typename = f"std::shared_ptr<{self.get_typename()}>" elif self.is_ptr: - typename = "{typename}*".format(typename=self.typename.to_cpp()) + typename = f"{self.typename.to_cpp()}*" elif self.is_ref: - typename = typename = "{typename}&".format( - typename=self.get_typename()) + typename = f"{self.get_typename()}&" else: typename = self.get_typename() - return ("{const}{typename}".format( - const="const " if self.is_const else "", typename=typename)) + const = "const " if self.is_const else "" + return f"{const}{typename}" class TemplatedType: @@ -265,7 +289,7 @@ def __init__(self, typename: Typename, template_params: List[Type], is_const: str, is_shared_ptr: str, is_ptr: str, is_ref: str): instantiations = [param.typename for param in template_params] # Recreate the typename but with the template params as instantiations. - self.typename = Typename(typename.namespaces + [typename.name], + self.typename = Typename(typename.name, typename.namespaces, instantiations) self.template_params = template_params @@ -278,22 +302,33 @@ def __init__(self, typename: Typename, template_params: List[Type], @staticmethod def from_parse_result(t: ParseResults): """Get the TemplatedType from the parser results.""" - return TemplatedType(t.typename, t.template_params, t.is_const, - t.is_shared_ptr, t.is_ptr, t.is_ref) + return TemplatedType(t.typename, t.template_params.as_list(), + t.is_const, t.is_shared_ptr, t.is_ptr, t.is_ref) def __repr__(self): - return "TemplatedType({typename.namespaces}::{typename.name})".format( - typename=self.typename) + return "TemplatedType({typename.namespaces}::{typename.name}<{template_params}>)".format( + typename=self.typename, template_params=self.template_params) + + def get_template_params(self): + """ + Get the template args for the type as a string. + E.g. for + ``` + template + class Random(){}; + ``` + it returns ``. + + """ + # Use Type.to_cpp to do the heavy lifting for the template parameters. + return ", ".join([t.to_cpp() for t in self.template_params]) def get_typename(self): """ Get the typename of this type without any qualifiers. E.g. for `const std::vector& indices` this will return `std::vector`. """ - # Use Type.to_cpp to do the heavy lifting for the template parameters. - template_args = ", ".join([t.to_cpp() for t in self.template_params]) - - return f"{self.typename.qualified_name()}<{template_args}>" + return f"{self.typename.qualified_name()}<{self.get_template_params()}>" def to_cpp(self): """ diff --git a/gtwrap/pybind_wrapper.py b/gtwrap/pybind_wrapper.py index b8d3d80..0c1e037 100755 --- a/gtwrap/pybind_wrapper.py +++ b/gtwrap/pybind_wrapper.py @@ -18,9 +18,10 @@ import gtwrap.interface_parser as parser import gtwrap.template_instantiator as instantiator - +from gtwrap.interface_parser.function import ArgumentList from gtwrap.xml_parser.xml_parser import XMLDocParser + class PybindWrapper: """ Class to generate binding code for Pybind11 specifically. @@ -30,7 +31,7 @@ def __init__(self, module_name, top_module_namespaces='', use_boost_serialization=False, - ignore_classes=(), + ignore_classes=(), module_template="", xml_source=""): self.module_name = module_name @@ -76,7 +77,7 @@ def _py_args_names(self, args): else: return '' - def _method_args_signature(self, args): + def _method_args_signature(self, args: ArgumentList): """Generate the argument types and names as per the method signature.""" cpp_types = args.to_cpp() names = args.names() @@ -260,37 +261,42 @@ def _wrap_method(self, args_names=', '.join(args_names), )) - ret = ('{prefix}.{cdef}("{py_method}",' - '[]({opt_self}{opt_comma}{args_signature_with_names}){{' - '{function_call}' - '}}' - '{py_args_names}{docstring}){suffix}'.format( - prefix=prefix, - cdef="def_static" if is_static else "def", - py_method=py_method, - opt_self="{cpp_class}* self".format( - cpp_class=cpp_class) if is_method else "", - opt_comma=', ' if is_method and args_names else '', - args_signature_with_names=args_signature_with_names, - function_call=function_call, - py_args_names=py_args_names, - suffix=suffix, - # Try to get the function's docstring from the Doxygen XML. - # If extract_docstring errors or fails to find a docstring, it just prints a warning. - # The incantation repr(...)[1:-1].replace('"', r'\"') replaces newlines with \n - # and " with \" so that the docstring can be put into a C++ string on a single line. - docstring=', "' + repr(self.xml_parser.extract_docstring(self.xml_source, cpp_class, cpp_method, method.args.names()))[1:-1].replace('"', r'\"') + '"' - if self.xml_source != "" else "", - )) + result = ( + '{prefix}.{cdef}("{py_method}",' + '[]({opt_self}{opt_comma}{args_signature_with_names}){{' + '{function_call}' + '}}' + '{py_args_names}{docstring}){suffix}'.format( + prefix=prefix, + cdef="def_static" if is_static else "def", + py_method=py_method, + opt_self="{cpp_class}* self".format( + cpp_class=cpp_class) if is_method else "", + opt_comma=', ' + if is_method and args_signature_with_names else '', + args_signature_with_names=args_signature_with_names, + function_call=function_call, + py_args_names=py_args_names, + suffix=suffix, + # Try to get the function's docstring from the Doxygen XML. + # If extract_docstring errors or fails to find a docstring, it just prints a warning. + # The incantation repr(...)[1:-1].replace('"', r'\"') replaces newlines with \n + # and " with \" so that the docstring can be put into a C++ string on a single line. + docstring=', "' + repr( + self.xml_parser.extract_docstring( + self.xml_source, cpp_class, cpp_method, + method.args.names()))[1:-1].replace('"', r'\"') + + '"' if self.xml_source != "" else "", + )) # Create __repr__ override # We allow all arguments to .print() and let the compiler handle type mismatches. if method.name == 'print': - ret = self._wrap_print(ret, method, cpp_class, args_names, - args_signature_with_names, py_args_names, - prefix, suffix) + result = self._wrap_print(result, method, cpp_class, args_names, + args_signature_with_names, py_args_names, + prefix, suffix) - return ret + return result def wrap_dunder_methods(self, methods, diff --git a/gtwrap/template_instantiator/classes.py b/gtwrap/template_instantiator/classes.py index 7026546..3e66f94 100644 --- a/gtwrap/template_instantiator/classes.py +++ b/gtwrap/template_instantiator/classes.py @@ -2,7 +2,8 @@ import gtwrap.interface_parser as parser from gtwrap.template_instantiator.constructor import InstantiatedConstructor -from gtwrap.template_instantiator.helpers import (InstantiationHelper, +from gtwrap.template_instantiator.helpers import (InstantiatedMember, + InstantiationHelper, instantiate_args_list, instantiate_name, instantiate_return_type, @@ -57,7 +58,7 @@ def __init__(self, original: parser.Class, instantiations=(), new_name=''): # Instantiate all instance methods self.methods = self.instantiate_methods(typenames) - + self.dunder_methods = original.dunder_methods super().__init__( @@ -99,9 +100,11 @@ def instantiate_parent_class(self, typenames): """ if isinstance(self.original.parent_class, parser.type.TemplatedType): - return instantiate_type( - self.original.parent_class, typenames, self.instantiations, - parser.Typename(self.namespaces())).typename + namespaces = self.namespaces() + typename = parser.Typename(name=namespaces[-1], + namespaces=namespaces[:-1]) + return instantiate_type(self.original.parent_class, typenames, + self.instantiations, typename).typename else: return self.original.parent_class @@ -140,7 +143,7 @@ def instantiate_static_methods(self, typenames): return instantiated_static_methods - def instantiate_methods(self, typenames): + def instantiate_methods(self, typenames) -> list[InstantiatedMember]: """ Instantiate regular methods in the class. @@ -225,9 +228,8 @@ def cpp_typename(self): ", ".join([inst.to_cpp() for inst in self.instantiations])) else: name = self.original.name - namespaces_name = self.namespaces() - namespaces_name.append(name) - return parser.Typename(namespaces_name) + + return parser.Typename(name=name, namespaces=self.namespaces()) def to_cpp(self): """Generate the C++ code for wrapping.""" diff --git a/gtwrap/template_instantiator/declaration.py b/gtwrap/template_instantiator/declaration.py index 4fa6b75..8fac6c2 100644 --- a/gtwrap/template_instantiator/declaration.py +++ b/gtwrap/template_instantiator/declaration.py @@ -35,10 +35,8 @@ def to_cpp(self): ] name = "{}<{}>".format(self.original.name, ",".join(instantiated_names)) - namespaces_name = self.namespaces() - namespaces_name.append(name) # Leverage Typename to generate the fully qualified C++ name - return parser.Typename(namespaces_name).to_cpp() + return parser.Typename(name=name, namespaces=self.namespaces()).to_cpp() def __repr__(self): return "Instantiated {}".format( diff --git a/gtwrap/template_instantiator/function.py b/gtwrap/template_instantiator/function.py index 1d304d6..ec7c829 100644 --- a/gtwrap/template_instantiator/function.py +++ b/gtwrap/template_instantiator/function.py @@ -65,4 +65,4 @@ def to_cpp(self): return ret def __repr__(self): - return f"Instantiated {super().__repr__}" + return f"Instantiated {super().__repr__()}" diff --git a/gtwrap/template_instantiator/helpers.py b/gtwrap/template_instantiator/helpers.py index ddcfbc8..1878d0d 100644 --- a/gtwrap/template_instantiator/helpers.py +++ b/gtwrap/template_instantiator/helpers.py @@ -2,16 +2,16 @@ import itertools from copy import deepcopy -from typing import List, Sequence, Union +from typing import Sequence, Union import gtwrap.interface_parser as parser -ClassMembers = Union[parser.Constructor, parser.Method, parser.StaticMethod, - parser.GlobalFunction, parser.Operator, parser.Variable, - parser.Enum] -InstantiatedMembers = Union['InstantiatedConstructor', 'InstantiatedMethod', - 'InstantiatedStaticMethod', - 'InstantiatedGlobalFunction'] +ClassMember = Union[parser.Constructor, parser.Method, parser.StaticMethod, + parser.GlobalFunction, parser.Operator, parser.Variable, + parser.Enum] +InstantiatedMember = Union['InstantiatedConstructor', 'InstantiatedMethod', + 'InstantiatedStaticMethod', + 'InstantiatedGlobalFunction'] def is_scoped_template(template_typenames: Sequence[str], @@ -76,11 +76,17 @@ def instantiate_type( if scoped_template: # Create a copy of the instantiation so we can modify it. instantiation = deepcopy(instantiations[scoped_idx]) + # Replace the part of the template with the instantiation - instantiation.name = str_arg_typename.replace(scoped_template, - instantiation.name) + # This new typename has the updated name, previous namespaces and no instantiations + new_typename = parser.type.Typename( + name=str_arg_typename.replace(scoped_template, + instantiation.templated_name()), + namespaces=instantiation.namespaces, + ) + return parser.Type( - typename=instantiation, + typename=new_typename, is_const=ctype.is_const, is_shared_ptr=ctype.is_shared_ptr, is_ptr=ctype.is_ptr, @@ -105,11 +111,9 @@ def instantiate_type( # Check if the class is template instantiated # so we can replace it with the instantiated version. if instantiated_class: - name = instantiated_class.original.name - namespaces_name = instantiated_class.namespaces() - namespaces_name.append(name) cpp_typename = parser.Typename( - namespaces_name, + name=instantiated_class.original.name, + namespaces=instantiated_class.namespaces(), instantiations=instantiated_class.instantiations) return parser.Type( @@ -209,7 +213,7 @@ def instantiate_name(original_name: str, # Using `capitalize` on the complete name causes other caps to be lower case instantiated_names.append(name.replace(name[0], name[0].capitalize())) - return "{}{}".format(original_name, "".join(instantiated_names)) + return f"{original_name}{''.join(instantiated_names)}" class InstantiationHelper: @@ -229,14 +233,13 @@ class InstantiationHelper: ``` """ - def __init__(self, instantiation_type: InstantiatedMembers): + def __init__(self, instantiation_type: InstantiatedMember): self.instantiation_type = instantiation_type - def instantiate(self, instantiated_methods: List[InstantiatedMembers], - method: ClassMembers, typenames: Sequence[str], + def instantiate(self, method: ClassMember, typenames: Sequence[str], class_instantiations: Sequence[parser.Typename], method_instantiations: Sequence[parser.Typename], - parent: 'InstantiatedClass'): + parent: 'InstantiatedClass') -> InstantiatedMember: """ Instantiate both the class and method level templates. """ @@ -246,19 +249,17 @@ def instantiate(self, instantiated_methods: List[InstantiatedMembers], typenames, instantiations, parent.cpp_typename()) - instantiated_methods.append( - self.instantiation_type.construct(method, - typenames, - class_instantiations, - method_instantiations, - instantiated_args, - parent=parent)) - - return instantiated_methods - - def multilevel_instantiation(self, methods_list: Sequence[ClassMembers], - typenames: Sequence[str], - parent: 'InstantiatedClass'): + return self.instantiation_type.construct(method, + typenames, + class_instantiations, + method_instantiations, + instantiated_args, + parent=parent) + + def multilevel_instantiation( + self, methods_list: Sequence[ClassMember], + typenames: Sequence[str], + parent: 'InstantiatedClass') -> list[InstantiatedMember]: """ Helper to instantiate methods at both the class and method level. @@ -280,22 +281,22 @@ def multilevel_instantiation(self, methods_list: Sequence[ClassMembers], for instantiations in itertools.product( *method.template.instantiations): - instantiated_methods = self.instantiate( - instantiated_methods, + instantiated_methods.append( + self.instantiate( + method, + typenames=method_typenames, + class_instantiations=parent.instantiations, + method_instantiations=list(instantiations), + parent=parent)) + + else: + # If no method level templates, just use the class templates + instantiated_methods.append( + self.instantiate( method, typenames=method_typenames, class_instantiations=parent.instantiations, - method_instantiations=list(instantiations), - parent=parent) - - else: - # If no constructor level templates, just use the class templates - instantiated_methods = self.instantiate( - instantiated_methods, - method, - typenames=method_typenames, - class_instantiations=parent.instantiations, - method_instantiations=[], - parent=parent) + method_instantiations=[], + parent=parent)) return instantiated_methods diff --git a/tests/expected/matlab/MyFactorPosePoint2.m b/tests/expected/matlab/MyFactorPosePoint2.m index 02016c6..264699b 100644 --- a/tests/expected/matlab/MyFactorPosePoint2.m +++ b/tests/expected/matlab/MyFactorPosePoint2.m @@ -15,9 +15,9 @@ function obj = MyFactorPosePoint2(varargin) if nargin == 2 && isa(varargin{1}, 'uint64') && varargin{1} == uint64(5139824614673773682) my_ptr = varargin{2}; - class_wrapper(83, my_ptr); + class_wrapper(87, my_ptr); elseif nargin == 4 && isa(varargin{1},'numeric') && isa(varargin{2},'numeric') && isa(varargin{3},'double') && isa(varargin{4},'gtsam.noiseModel.Base') - my_ptr = class_wrapper(84, varargin{1}, varargin{2}, varargin{3}, varargin{4}); + my_ptr = class_wrapper(88, varargin{1}, varargin{2}, varargin{3}, varargin{4}); else error('Arguments do not match any overload of MyFactorPosePoint2 constructor'); end @@ -25,7 +25,7 @@ end function delete(obj) - class_wrapper(85, obj.ptr_MyFactorPosePoint2); + class_wrapper(89, obj.ptr_MyFactorPosePoint2); end function display(obj), obj.print(''); end @@ -36,19 +36,19 @@ function delete(obj) % PRINT usage: print(string s, KeyFormatter keyFormatter) : returns void % Doxygen can be found at https://gtsam.org/doxygen/ if length(varargin) == 2 && isa(varargin{1},'char') && isa(varargin{2},'gtsam.KeyFormatter') - class_wrapper(86, this, varargin{:}); + class_wrapper(90, this, varargin{:}); return end % PRINT usage: print(string s) : returns void % Doxygen can be found at https://gtsam.org/doxygen/ if length(varargin) == 1 && isa(varargin{1},'char') - class_wrapper(87, this, varargin{:}); + class_wrapper(91, this, varargin{:}); return end % PRINT usage: print() : returns void % Doxygen can be found at https://gtsam.org/doxygen/ if length(varargin) == 0 - class_wrapper(88, this, varargin{:}); + class_wrapper(92, this, varargin{:}); return end error('Arguments do not match any overload of function MyFactorPosePoint2.print'); diff --git a/tests/expected/matlab/SmartProjectionRigFactorPinholeCameraCal3_S2.m b/tests/expected/matlab/SmartProjectionRigFactorPinholeCameraCal3_S2.m new file mode 100644 index 0000000..2ad7ed7 --- /dev/null +++ b/tests/expected/matlab/SmartProjectionRigFactorPinholeCameraCal3_S2.m @@ -0,0 +1,51 @@ +%class SmartProjectionRigFactorPinholeCameraCal3_S2, see Doxygen page for details +%at https://gtsam.org/doxygen/ +% +%-------Methods------- +%add(PinholeCamera::Measurement measured, Key poseKey, size_t cameraId) : returns void +% +classdef SmartProjectionRigFactorPinholeCameraCal3_S2 < gtsam.SmartProjectionFactor> + properties + ptr_SmartProjectionRigFactorPinholeCameraCal3_S2 = 0 + end + methods + function obj = SmartProjectionRigFactorPinholeCameraCal3_S2(varargin) + if nargin == 2 && isa(varargin{1}, 'uint64') && varargin{1} == uint64(5139824614673773682) + my_ptr = varargin{2}; + base_ptr = class_wrapper(83, my_ptr); + else + error('Arguments do not match any overload of SmartProjectionRigFactorPinholeCameraCal3_S2 constructor'); + end + obj = obj@gtsam.SmartProjectionFactorgtsam::PinholeCamera(uint64(5139824614673773682), base_ptr); + obj.ptr_SmartProjectionRigFactorPinholeCameraCal3_S2 = my_ptr; + end + + function delete(obj) + class_wrapper(84, obj.ptr_SmartProjectionRigFactorPinholeCameraCal3_S2); + 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 + function varargout = add(this, varargin) + % ADD usage: add(PinholeCamera::Measurement measured, Key poseKey, size_t cameraId) : returns void + % Doxygen can be found at https://gtsam.org/doxygen/ + if length(varargin) == 3 && isa(varargin{1},'gtsam.PinholeCamera::Measurement') && isa(varargin{2},'numeric') && isa(varargin{3},'numeric') + class_wrapper(85, this, varargin{:}); + return + end + % ADD usage: add(PinholeCamera::Measurement measured, Key poseKey) : returns void + % Doxygen can be found at https://gtsam.org/doxygen/ + if length(varargin) == 2 && isa(varargin{1},'gtsam.PinholeCamera::Measurement') && isa(varargin{2},'numeric') + class_wrapper(86, this, varargin{:}); + return + end + error('Arguments do not match any overload of function SmartProjectionRigFactorPinholeCameraCal3_S2.add'); + end + + end + + methods(Static = true) + end +end diff --git a/tests/expected/matlab/class_wrapper.cpp b/tests/expected/matlab/class_wrapper.cpp index 8462aa4..ed57b38 100644 --- a/tests/expected/matlab/class_wrapper.cpp +++ b/tests/expected/matlab/class_wrapper.cpp @@ -9,6 +9,7 @@ typedef MyVector<3> MyVector3; typedef MyVector<12> MyVector12; typedef MultipleTemplates MultipleTemplatesIntDouble; typedef MultipleTemplates MultipleTemplatesIntFloat; +typedef SmartProjectionRigFactor> SmartProjectionRigFactorPinholeCameraCal3_S2; typedef MyFactor MyFactorPosePoint2; typedef std::set*> Collector_FunRange; @@ -35,6 +36,8 @@ typedef std::set*> Collector_FastSet; static Collector_FastSet collector_FastSet; typedef std::set*> Collector_HessianFactor; static Collector_HessianFactor collector_HessianFactor; +typedef std::set*> Collector_SmartProjectionRigFactorPinholeCameraCal3_S2; +static Collector_SmartProjectionRigFactorPinholeCameraCal3_S2 collector_SmartProjectionRigFactorPinholeCameraCal3_S2; typedef std::set*> Collector_MyFactorPosePoint2; static Collector_MyFactorPosePoint2 collector_MyFactorPosePoint2; @@ -117,6 +120,12 @@ void _deleteAllObjects() collector_HessianFactor.erase(iter++); anyDeleted = true; } } + { for(Collector_SmartProjectionRigFactorPinholeCameraCal3_S2::iterator iter = collector_SmartProjectionRigFactorPinholeCameraCal3_S2.begin(); + iter != collector_SmartProjectionRigFactorPinholeCameraCal3_S2.end(); ) { + delete *iter; + collector_SmartProjectionRigFactorPinholeCameraCal3_S2.erase(iter++); + anyDeleted = true; + } } { for(Collector_MyFactorPosePoint2::iterator iter = collector_MyFactorPosePoint2.begin(); iter != collector_MyFactorPosePoint2.end(); ) { delete *iter; @@ -972,7 +981,52 @@ void HessianFactor_deconstructor_82(int nargout, mxArray *out[], int nargin, con delete self; } -void MyFactorPosePoint2_collectorInsertAndMakeBase_83(int nargout, mxArray *out[], int nargin, const mxArray *in[]) +void SmartProjectionRigFactorPinholeCameraCal3_S2_collectorInsertAndMakeBase_83(int nargout, mxArray *out[], int nargin, const mxArray *in[]) +{ + mexAtExit(&_deleteAllObjects); + typedef std::shared_ptr>> Shared; + + Shared *self = *reinterpret_cast (mxGetData(in[0])); + collector_SmartProjectionRigFactorPinholeCameraCal3_S2.insert(self); + + typedef std::shared_ptr>> SharedBase; + out[0] = mxCreateNumericMatrix(1, 1, mxUINT32OR64_CLASS, mxREAL); + *reinterpret_cast(mxGetData(out[0])) = new SharedBase(*self); +} + +void SmartProjectionRigFactorPinholeCameraCal3_S2_deconstructor_84(int nargout, mxArray *out[], int nargin, const mxArray *in[]) +{ + typedef std::shared_ptr>> Shared; + checkArguments("delete_SmartProjectionRigFactorPinholeCameraCal3_S2",nargout,nargin,1); + Shared *self = *reinterpret_cast(mxGetData(in[0])); + Collector_SmartProjectionRigFactorPinholeCameraCal3_S2::iterator item; + item = collector_SmartProjectionRigFactorPinholeCameraCal3_S2.find(self); + if(item != collector_SmartProjectionRigFactorPinholeCameraCal3_S2.end()) { + collector_SmartProjectionRigFactorPinholeCameraCal3_S2.erase(item); + } + delete self; +} + +void SmartProjectionRigFactorPinholeCameraCal3_S2_add_85(int nargout, mxArray *out[], int nargin, const mxArray *in[]) +{ + checkArguments("add",nargout,nargin-1,3); + auto obj = unwrap_shared_ptr>>(in[0], "ptr_SmartProjectionRigFactorPinholeCameraCal3_S2"); + gtsam::PinholeCamera::Measurement& measured = *unwrap_shared_ptr< gtsam::PinholeCamera::Measurement >(in[1], "ptr_gtsamPinholeCamera::Measurement"); + gtsam::Key poseKey = unwrap< gtsam::Key >(in[2]); + size_t cameraId = unwrap< size_t >(in[3]); + obj->add(measured,poseKey,cameraId); +} + +void SmartProjectionRigFactorPinholeCameraCal3_S2_add_86(int nargout, mxArray *out[], int nargin, const mxArray *in[]) +{ + checkArguments("add",nargout,nargin-1,2); + auto obj = unwrap_shared_ptr>>(in[0], "ptr_SmartProjectionRigFactorPinholeCameraCal3_S2"); + gtsam::PinholeCamera::Measurement& measured = *unwrap_shared_ptr< gtsam::PinholeCamera::Measurement >(in[1], "ptr_gtsamPinholeCamera::Measurement"); + gtsam::Key poseKey = unwrap< gtsam::Key >(in[2]); + obj->add(measured,poseKey,0); +} + +void MyFactorPosePoint2_collectorInsertAndMakeBase_87(int nargout, mxArray *out[], int nargin, const mxArray *in[]) { mexAtExit(&_deleteAllObjects); typedef std::shared_ptr> Shared; @@ -981,7 +1035,7 @@ void MyFactorPosePoint2_collectorInsertAndMakeBase_83(int nargout, mxArray *out[ collector_MyFactorPosePoint2.insert(self); } -void MyFactorPosePoint2_constructor_84(int nargout, mxArray *out[], int nargin, const mxArray *in[]) +void MyFactorPosePoint2_constructor_88(int nargout, mxArray *out[], int nargin, const mxArray *in[]) { mexAtExit(&_deleteAllObjects); typedef std::shared_ptr> Shared; @@ -996,7 +1050,7 @@ void MyFactorPosePoint2_constructor_84(int nargout, mxArray *out[], int nargin, *reinterpret_cast (mxGetData(out[0])) = self; } -void MyFactorPosePoint2_deconstructor_85(int nargout, mxArray *out[], int nargin, const mxArray *in[]) +void MyFactorPosePoint2_deconstructor_89(int nargout, mxArray *out[], int nargin, const mxArray *in[]) { typedef std::shared_ptr> Shared; checkArguments("delete_MyFactorPosePoint2",nargout,nargin,1); @@ -1009,7 +1063,7 @@ void MyFactorPosePoint2_deconstructor_85(int nargout, mxArray *out[], int nargin delete self; } -void MyFactorPosePoint2_print_86(int nargout, mxArray *out[], int nargin, const mxArray *in[]) +void MyFactorPosePoint2_print_90(int nargout, mxArray *out[], int nargin, const mxArray *in[]) { checkArguments("print",nargout,nargin-1,2); auto obj = unwrap_shared_ptr>(in[0], "ptr_MyFactorPosePoint2"); @@ -1018,7 +1072,7 @@ void MyFactorPosePoint2_print_86(int nargout, mxArray *out[], int nargin, const obj->print(s,keyFormatter); } -void MyFactorPosePoint2_print_87(int nargout, mxArray *out[], int nargin, const mxArray *in[]) +void MyFactorPosePoint2_print_91(int nargout, mxArray *out[], int nargin, const mxArray *in[]) { checkArguments("print",nargout,nargin-1,1); auto obj = unwrap_shared_ptr>(in[0], "ptr_MyFactorPosePoint2"); @@ -1026,7 +1080,7 @@ void MyFactorPosePoint2_print_87(int nargout, mxArray *out[], int nargin, const obj->print(s,gtsam::DefaultKeyFormatter); } -void MyFactorPosePoint2_print_88(int nargout, mxArray *out[], int nargin, const mxArray *in[]) +void MyFactorPosePoint2_print_92(int nargout, mxArray *out[], int nargin, const mxArray *in[]) { checkArguments("print",nargout,nargin-1,0); auto obj = unwrap_shared_ptr>(in[0], "ptr_MyFactorPosePoint2"); @@ -1295,22 +1349,34 @@ void mexFunction(int nargout, mxArray *out[], int nargin, const mxArray *in[]) HessianFactor_deconstructor_82(nargout, out, nargin-1, in+1); break; case 83: - MyFactorPosePoint2_collectorInsertAndMakeBase_83(nargout, out, nargin-1, in+1); + SmartProjectionRigFactorPinholeCameraCal3_S2_collectorInsertAndMakeBase_83(nargout, out, nargin-1, in+1); break; case 84: - MyFactorPosePoint2_constructor_84(nargout, out, nargin-1, in+1); + SmartProjectionRigFactorPinholeCameraCal3_S2_deconstructor_84(nargout, out, nargin-1, in+1); break; case 85: - MyFactorPosePoint2_deconstructor_85(nargout, out, nargin-1, in+1); + SmartProjectionRigFactorPinholeCameraCal3_S2_add_85(nargout, out, nargin-1, in+1); break; case 86: - MyFactorPosePoint2_print_86(nargout, out, nargin-1, in+1); + SmartProjectionRigFactorPinholeCameraCal3_S2_add_86(nargout, out, nargin-1, in+1); break; case 87: - MyFactorPosePoint2_print_87(nargout, out, nargin-1, in+1); + MyFactorPosePoint2_collectorInsertAndMakeBase_87(nargout, out, nargin-1, in+1); break; case 88: - MyFactorPosePoint2_print_88(nargout, out, nargin-1, in+1); + MyFactorPosePoint2_constructor_88(nargout, out, nargin-1, in+1); + break; + case 89: + MyFactorPosePoint2_deconstructor_89(nargout, out, nargin-1, in+1); + break; + case 90: + MyFactorPosePoint2_print_90(nargout, out, nargin-1, in+1); + break; + case 91: + MyFactorPosePoint2_print_91(nargout, out, nargin-1, in+1); + break; + case 92: + MyFactorPosePoint2_print_92(nargout, out, nargin-1, in+1); break; } } catch(const std::exception& e) { diff --git a/tests/expected/python/class_pybind.cpp b/tests/expected/python/class_pybind.cpp index 38915d1..f22e80a 100644 --- a/tests/expected/python/class_pybind.cpp +++ b/tests/expected/python/class_pybind.cpp @@ -103,6 +103,9 @@ PYBIND11_MODULE(class_py, m_) { py::class_>(m_, "HessianFactor") .def(py::init&, const std::vector&, double>(), py::arg("js"), py::arg("Gs"), py::arg("gs"), py::arg("f")); + py::class_>, gtsam::SmartProjectionFactor>, std::shared_ptr>>>(m_, "SmartProjectionRigFactorPinholeCameraCal3_S2") + .def("add",[](SmartProjectionRigFactor>* self, const gtsam::PinholeCamera::Measurement& measured, const gtsam::Key& poseKey, const size_t& cameraId){ self->add(measured, poseKey, cameraId);}, py::arg("measured"), py::arg("poseKey"), py::arg("cameraId") = 0); + py::class_, std::shared_ptr>>(m_, "MyFactorPosePoint2") .def(py::init>(), py::arg("key1"), py::arg("key2"), py::arg("measured"), py::arg("noiseModel")) .def("print",[](MyFactor* self, const string& s, const gtsam::KeyFormatter& keyFormatter){ py::scoped_ostream_redirect output; self->print(s, keyFormatter);}, py::arg("s") = "factor: ", py::arg("keyFormatter") = gtsam::DefaultKeyFormatter) diff --git a/tests/fixtures/class.i b/tests/fixtures/class.i index 6cc0de5..745e4be 100644 --- a/tests/fixtures/class.i +++ b/tests/fixtures/class.i @@ -7,29 +7,26 @@ class FunRange { void serialize() const; }; -template +template class Fun { - static This staticMethodWithThis(); - template + template static double templatedStaticMethod(const T& m); - template + template This templatedMethod(double d, T t); - template + template This multiTemplatedMethod(double d, T t, U u); std::map sets(); }; - // An include! Can go anywhere outside of a class, in any order #include class Test { - /* a comment! */ // another comment Test(); @@ -42,21 +39,24 @@ class Test { string name; // intentionally the first method - pair return_pair (const gtsam::Vector& v, const gtsam::Matrix& A) const; - pair return_pair (const gtsam::Vector& v) const; // overload + pair return_pair(const gtsam::Vector& v, + const gtsam::Matrix& A) const; + pair return_pair( + const gtsam::Vector& v) const; // overload - bool return_bool (bool value) const; // comment after a line! - size_t return_size_t (size_t value) const; - int return_int (int value) const; - double return_double (double value) const; + bool return_bool(bool value) const; // comment after a line! + size_t return_size_t(size_t value) const; + int return_int(int value) const; + double return_double(double value) const; - Test(double a, const gtsam::Matrix& b); // a constructor in the middle of a class + Test(double a, + const gtsam::Matrix& b); // a constructor in the middle of a class // comments in the middle! // (more) comments in the middle! - string return_string (string value) const; + string return_string(string value) const; gtsam::Vector return_vector1(const gtsam::Vector& value) const; gtsam::Matrix return_matrix1(const gtsam::Matrix& value) const; gtsam::Vector return_vector2(const gtsam::Vector& value) const; @@ -72,13 +72,13 @@ class Test { bool return_field(const Test& t) const; Test* return_TestPtr(const Test* value) const; - Test return_Test(Test* value) const; + Test return_Test(Test* value) const; gtsam::Point2* return_Point2Ptr(bool value) const; - pair create_ptrs () const; - pair create_MixedPtrs () const; - pair return_ptrs (Test* p1, Test* p2) const; + pair create_ptrs() const; + pair create_MixedPtrs() const; + pair return_ptrs(Test* p1, Test* p2) const; // This should be callable as .print() in python void print() const; @@ -92,7 +92,7 @@ class Test { // special ipython method string markdown(const gtsam::KeyFormatter& keyFormatter = - gtsam::DefaultKeyFormatter) const; + gtsam::DefaultKeyFormatter) const; // comments at the end! @@ -102,17 +102,19 @@ class Test { virtual class ns::OtherClass; // A doubly templated class -template +template class MyFactor { - MyFactor(size_t key1, size_t key2, double measured, const gtsam::noiseModel::Base* noiseModel); - void print(const string &s = "factor: ", - const gtsam::KeyFormatter &keyFormatter = gtsam::DefaultKeyFormatter); + MyFactor(size_t key1, size_t key2, double measured, + const gtsam::noiseModel::Base* noiseModel); + void print( + const string& s = "factor: ", + const gtsam::KeyFormatter& keyFormatter = gtsam::DefaultKeyFormatter); }; // and a typedef specializing it typedef MyFactor MyFactorPosePoint2; -template +template class PrimitiveRef { PrimitiveRef(); @@ -120,7 +122,7 @@ class PrimitiveRef { }; // A class with integer template arguments -template +template class MyVector { MyVector(); }; @@ -130,7 +132,7 @@ class MyVector { // even more comments at the end! // Class with multiple instantiated templates -template +template class MultipleTemplates {}; // Test for default args in constructor @@ -145,11 +147,10 @@ class ForwardKinematics { class TemplatedConstructor { TemplatedConstructor(); - template + template TemplatedConstructor(const T& arg); }; - class SuperCoolFactor; typedef SuperCoolFactor SuperCoolFactorPose3; @@ -167,3 +168,9 @@ virtual class HessianFactor : gtsam::GaussianFactor { const std::vector& Gs, const std::vector& gs, double f); }; + +template }> +class SmartProjectionRigFactor : gtsam::SmartProjectionFactor { + void add(const CAMERA::Measurement& measured, const gtsam::Key& poseKey, + const size_t& cameraId = 0); +}; diff --git a/tests/test_matlab_wrapper.py b/tests/test_matlab_wrapper.py index 34bee7d..e95ca88 100644 --- a/tests/test_matlab_wrapper.py +++ b/tests/test_matlab_wrapper.py @@ -141,6 +141,7 @@ def test_class(self): 'MyVector3.m', 'MyVector12.m', 'PrimitiveRefDouble.m', + 'SmartProjectionRigFactorPinholeCameraCal3_S2.m', 'Test.m', ] diff --git a/tests/test_template_instantiator.py b/tests/test_template_instantiator.py index 4faf01a..657946e 100644 --- a/tests/test_template_instantiator.py +++ b/tests/test_template_instantiator.py @@ -23,16 +23,23 @@ GlobalFunction, Include, Method, Namespace, ReturnType, StaticMethod, Typename) -from gtwrap.template_instantiator import ( - InstantiatedClass, InstantiatedConstructor, InstantiatedDeclaration, - InstantiatedGlobalFunction, InstantiatedMethod, InstantiatedStaticMethod, - InstantiationHelper, instantiate_args_list, instantiate_name, - instantiate_namespace, instantiate_return_type, instantiate_type, - is_scoped_template) +from gtwrap.template_instantiator import (InstantiatedClass, + InstantiatedConstructor, + InstantiatedDeclaration, + InstantiatedGlobalFunction, + InstantiatedMethod, + InstantiatedStaticMethod, + InstantiationHelper, + instantiate_args_list, + instantiate_name, + instantiate_namespace, + instantiate_return_type, + instantiate_type, is_scoped_template) class TestInstantiationHelper(unittest.TestCase): """Tests for the InstantiationHelper class.""" + def test_constructor(self): """Test constructor.""" helper = InstantiationHelper(InstantiatedClass) @@ -65,10 +72,10 @@ class Foo {}; parent = InstantiatedClass(cls, class_instantiations) helper = InstantiationHelper(InstantiatedMethod) - instantiated_methods = helper.instantiate([], method, typenames, - class_instantiations, - method_instantiations, - parent) + instantiated_methods = [ + helper.instantiate(method, typenames, class_instantiations, + method_instantiations, parent) + ] self.assertEqual(len(instantiated_methods), 1) args_list = instantiated_methods[0].args.list() @@ -115,6 +122,7 @@ class Foo { class TestInstantiatedGlobalFunction(unittest.TestCase): """Tests for the InstantiatedGlobalFunction class.""" + def setUp(self): original = GlobalFunction.rule.parseString(""" template @@ -143,6 +151,7 @@ def test_to_cpp(self): class TestInstantiatedConstructor(unittest.TestCase): """Tests for the InstantiatedConstructor class.""" + def setUp(self): constructor = Constructor.rule.parseString(""" template @@ -197,6 +206,7 @@ def test_to_cpp(self): class TestInstantiatedMethod(unittest.TestCase): """Tests for the InstantiatedMethod class.""" + def setUp(self): method = Method.rule.parseString(""" template @@ -248,6 +258,7 @@ def test_to_cpp(self): class TestInstantiatedStaticMethod(unittest.TestCase): """Tests for the InstantiatedStaticMethod class.""" + def setUp(self): static_method = StaticMethod.rule.parseString(""" template @@ -302,6 +313,7 @@ def test_to_cpp(self): class TestInstantiatedClass(unittest.TestCase): """Tests for the InstantiatedClass class.""" + def setUp(self): cl = Class.rule.parseString(""" template @@ -391,6 +403,7 @@ def test_to_cpp(self): class TestInstantiatedDeclaration(unittest.TestCase): """Tests for the InstantiatedDeclaration class.""" + def setUp(self): #TODO(Varun) Need to support templated class forward declaration. forward_declaration = ForwardDeclaration.rule.parseString(""" @@ -416,6 +429,7 @@ class TestTemplateInstantiator(unittest.TestCase): """ Test overall template instantiation and the functions in the module. """ + def test_scoped_template(self): """Test is_scoped_template.""" # Test if not scoped template.