Merging 'master' into 'wrap'

release/4.3a0
Varun Agrawal 2021-03-24 00:36:02 -04:00
commit 54e5dc23aa
36 changed files with 2386 additions and 1560 deletions

View File

@ -1,52 +0,0 @@
name: Python CI
on: [push, pull_request]
jobs:
build:
name: ${{ matrix.name }} 🐍 ${{ matrix.python_version }}
runs-on: ${{ matrix.os }}
env:
PYTHON_VERSION: ${{ matrix.python_version }}
strategy:
fail-fast: false
matrix:
# Github Actions requires a single row to be added to the build matrix.
# See https://help.github.com/en/articles/workflow-syntax-for-github-actions.
name: [
ubuntu-18.04
]
python_version: [3]
include:
- name: ubuntu-18.04
os: ubuntu-18.04
steps:
- name: Checkout
uses: actions/checkout@master
- name: Install (Linux)
if: runner.os == 'Linux'
run: |
sudo apt-get -y update
sudo apt install cmake build-essential pkg-config libpython-dev python-numpy libboost-all-dev
- name: Install (macOS)
if: runner.os == 'macOS'
run: |
brew install cmake ninja boost
- name: Build (Linux)
if: runner.os == 'Linux'
run: |
sudo pip$PYTHON_VERSION install -r requirements.txt
cd tests
python$PYTHON_VERSION test_pybind_wrapper.py
python$PYTHON_VERSION test_matlab_wrapper.py
- name: Build (macOS)
if: runner.os == 'macOS'
run: |
pip$PYTHON_VERSION install -r requirements.txt
cd tests
python$PYTHON_VERSION test_pybind_wrapper.py
python$PYTHON_VERSION test_matlab_wrapper.py

38
wrap/.github/workflows/linux-ci.yml vendored Normal file
View File

@ -0,0 +1,38 @@
name: Wrap CI for Linux
on: [pull_request]
jobs:
build:
name: Tests for 🐍 ${{ matrix.python-version }}
runs-on: ubuntu-18.04
strategy:
fail-fast: false
matrix:
python-version: [3.6, 3.7, 3.8, 3.9]
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Install Dependencies
run: |
sudo apt-get -y update
sudo apt install cmake build-essential pkg-config libpython-dev python-numpy libboost-all-dev
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v2
with:
python-version: ${{ matrix.python-version }}
- name: Python Dependencies
run: |
sudo pip3 install -U pip setuptools
sudo pip3 install -r requirements.txt
- name: Build and Test
run: |
cd tests
# Use Pytest to run all the tests.
pytest

36
wrap/.github/workflows/macos-ci.yml vendored Normal file
View File

@ -0,0 +1,36 @@
name: Wrap CI for macOS
on: [pull_request]
jobs:
build:
name: Tests for 🐍 ${{ matrix.python-version }}
runs-on: macos-10.15
strategy:
fail-fast: false
matrix:
python-version: [3.6, 3.7, 3.8, 3.9]
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Install Dependencies
run: |
brew install cmake ninja boost
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v2
with:
python-version: ${{ matrix.python-version }}
- name: Python Dependencies
run: |
pip3 install -r requirements.txt
- name: Build and Test
run: |
cd tests
# Use Pytest to run all the tests.
pytest

3
wrap/.gitignore vendored
View File

@ -3,3 +3,6 @@ __pycache__/
*build*
*dist*
*.egg-info
# Files related to code coverage stats
**/.coverage

View File

@ -31,17 +31,17 @@ include(GNUInstallDirs)
# Install the gtwrap python package as a directory so it can be found by CMake
# for wrapping.
install(DIRECTORY gtwrap DESTINATION "${CMAKE_INSTALL_DATADIR}/gtwrap")
install(DIRECTORY gtwrap DESTINATION "${CMAKE_INSTALL_FULL_LIBDIR}/gtwrap")
# Install wrapping scripts as binaries to `CMAKE_INSTALL_PREFIX/bin` so they can
# be invoked for wrapping. We use DESTINATION (instead of TYPE) so we can
# support older CMake versions.
install(PROGRAMS scripts/pybind_wrap.py scripts/matlab_wrap.py
DESTINATION ${CMAKE_INSTALL_BINDIR})
DESTINATION ${CMAKE_INSTALL_FULL_BINDIR})
# Install pybind11 directory to `CMAKE_INSTALL_PREFIX/lib/gtwrap/pybind11` This
# will allow the gtwrapConfig.cmake file to load it later.
install(DIRECTORY pybind11 DESTINATION "${CMAKE_INSTALL_LIBDIR}/gtwrap")
install(DIRECTORY pybind11 DESTINATION "${CMAKE_INSTALL_FULL_LIBDIR}/gtwrap")
# Install the matlab.h file to `CMAKE_INSTALL_PREFIX/lib/gtwrap/matlab.h`.
install(FILES matlab.h DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/gtwrap")
install(FILES matlab.h DESTINATION "${CMAKE_INSTALL_FULL_INCLUDEDIR}/gtwrap")

View File

@ -52,8 +52,8 @@ The python wrapper supports keyword arguments for functions/methods. Hence, the
- 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.
- To declare a simple/raw pointer, simply add an `@` to the class name, e.g.`Pose3@`.
- To declare a shared pointer (e.g. `gtsam::noiseModel::Base::shared_ptr`), use an asterisk (i.e. `*`). 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.
@ -76,9 +76,13 @@ The python wrapper supports keyword arguments for functions/methods. Hence, the
- 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.
- Functions can be templated and have multiple template arguments, e.g.
```cpp
template<T, >
```
- 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.
- 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. `OtherClass` should be in the same project.
- Virtual inheritance
- Specify fully-qualified base classes, i.e. `virtual class Derived : ns::Base {` where `ns` is the namespace.
@ -140,9 +144,9 @@ The python wrapper supports keyword arguments for functions/methods. Hence, the
- 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.
- This is so that Pybind can generate proper inheritance.
Example when wrapping a gtsam-based project:
- Example for when wrapping a gtsam-based project:
```cpp
// forward declarations
@ -153,8 +157,7 @@ The python wrapper supports keyword arguments for functions/methods. Hence, the
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.
- **DO NOT** re-define an overriden function already declared in the external (forward-declared) base class. This will cause an ambiguity problem in the Pybind header file.
### TODO

View File

@ -1,24 +1,25 @@
# This config file modifies CMAKE_MODULE_PATH so that the wrap cmake files may
# be included This file also allows the use of `find_package(gtwrap)` in CMake.
set(GTWRAP_DIR "${CMAKE_CURRENT_LIST_DIR}")
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}")
if(WIN32 AND NOT CYGWIN)
set(GTWRAP_CMAKE_DIR "${GTWRAP_DIR}")
set(GTWRAP_SCRIPT_DIR ${GTWRAP_CMAKE_DIR}/../../../bin)
set(GTWRAP_PYTHON_PACKAGE_DIR ${GTWRAP_CMAKE_DIR}/../../../share/gtwrap)
else()
set(GTWRAP_CMAKE_DIR "${GTWRAP_DIR}")
set(GTWRAP_SCRIPT_DIR ${GTWRAP_CMAKE_DIR}/../../../bin)
set(GTWRAP_PYTHON_PACKAGE_DIR ${GTWRAP_CMAKE_DIR}/../../../share/gtwrap)
endif()
# Standard includes
include(GNUInstallDirs)
include(CMakePackageConfigHelpers)
include(CMakeDependentOption)
set(GTWRAP_DIR "${CMAKE_CURRENT_LIST_DIR}")
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}")
if(WIN32 AND NOT CYGWIN)
set(GTWRAP_CMAKE_DIR "${GTWRAP_DIR}")
set(GTWRAP_SCRIPT_DIR ${CMAKE_INSTALL_FULL_BINDIR})
set(GTWRAP_PYTHON_PACKAGE_DIR ${CMAKE_INSTALL_FULL_LIBDIR}/gtwrap)
else()
set(GTWRAP_CMAKE_DIR "${GTWRAP_DIR}")
set(GTWRAP_SCRIPT_DIR ${CMAKE_INSTALL_FULL_BINDIR})
set(GTWRAP_PYTHON_PACKAGE_DIR ${CMAKE_INSTALL_FULL_LIBDIR}/gtwrap)
endif()
# Load all the CMake scripts from the standard location
include(${GTWRAP_CMAKE_DIR}/PybindWrap.cmake)
include(${GTWRAP_CMAKE_DIR}/GtwrapUtils.cmake)
@ -28,4 +29,4 @@ set(PYBIND_WRAP_SCRIPT "${GTWRAP_SCRIPT_DIR}/pybind_wrap.py")
set(MATLAB_WRAP_SCRIPT "${GTWRAP_SCRIPT_DIR}/matlab_wrap.py")
# Load the pybind11 code from the library installation path
add_subdirectory(${GTWRAP_CMAKE_DIR}/../../gtwrap/pybind11 pybind11)
add_subdirectory(${CMAKE_INSTALL_FULL_LIBDIR}/gtwrap/pybind11 pybind11)

View File

@ -1,4 +1,4 @@
# Doxyfile 1.8.11
# Doxyfile 1.9.1
# This file describes the settings to be used by the documentation system
# doxygen (www.doxygen.org) for a project.
@ -17,11 +17,11 @@
# Project related configuration options
#---------------------------------------------------------------------------
# This tag specifies the encoding used for all characters in the config file
# that follow. The default is UTF-8 which is also the encoding used for all text
# before the first occurrence of this tag. Doxygen uses libiconv (or the iconv
# built into libc) for the transcoding. See http://www.gnu.org/software/libiconv
# for the list of possible encodings.
# This tag specifies the encoding used for all characters in the configuration
# file that follow. The default is UTF-8 which is also the encoding used for all
# text before the first occurrence of this tag. Doxygen uses libiconv (or the
# iconv built into libc) for the transcoding. See
# https://www.gnu.org/software/libiconv/ for the list of possible encodings.
# The default value is: UTF-8.
DOXYFILE_ENCODING = UTF-8
@ -32,7 +32,7 @@ DOXYFILE_ENCODING = UTF-8
# title of most generated pages and in a few other places.
# The default value is: My Project.
PROJECT_NAME = "GTSAM"
PROJECT_NAME = GTSAM
# The PROJECT_NUMBER tag can be used to enter a project or revision number. This
# could be handy for archiving the generated documentation or if some version
@ -93,6 +93,14 @@ ALLOW_UNICODE_NAMES = NO
OUTPUT_LANGUAGE = English
# The OUTPUT_TEXT_DIRECTION tag is used to specify the direction in which all
# documentation generated by doxygen is written. Doxygen will use this
# information to generate all generated output in the proper direction.
# Possible values are: None, LTR, RTL and Context.
# The default value is: None.
OUTPUT_TEXT_DIRECTION = None
# If the BRIEF_MEMBER_DESC tag is set to YES, doxygen will include brief member
# descriptions after the members that are listed in the file and class
# documentation (similar to Javadoc). Set to NO to disable this.
@ -179,6 +187,16 @@ SHORT_NAMES = NO
JAVADOC_AUTOBRIEF = NO
# If the JAVADOC_BANNER tag is set to YES then doxygen will interpret a line
# such as
# /***************
# as being the beginning of a Javadoc-style comment "banner". If set to NO, the
# Javadoc-style will behave just like regular comments and it will not be
# interpreted by doxygen.
# The default value is: NO.
JAVADOC_BANNER = NO
# If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first
# line (until the first dot) of a Qt-style comment as the brief description. If
# set to NO, the Qt-style will behave just like regular Qt-style comments (thus
@ -199,6 +217,14 @@ QT_AUTOBRIEF = NO
MULTILINE_CPP_IS_BRIEF = NO
# By default Python docstrings are displayed as preformatted text and doxygen's
# special commands cannot be used. By setting PYTHON_DOCSTRING to NO the
# doxygen's special commands can be used and the contents of the docstring
# documentation blocks is shown as doxygen documentation.
# The default value is: YES.
PYTHON_DOCSTRING = YES
# If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the
# documentation from any documented member that it re-implements.
# The default value is: YES.
@ -226,16 +252,15 @@ TAB_SIZE = 4
# will allow you to put the command \sideeffect (or @sideeffect) in the
# documentation, which will result in a user-defined paragraph with heading
# "Side Effects:". You can put \n's in the value part of an alias to insert
# newlines.
# newlines (in the resulting output). You can put ^^ in the value part of an
# alias to insert a newline as if a physical newline was in the original file.
# When you need a literal { or } or , in the value part of an alias you have to
# escape them by means of a backslash (\), this can lead to conflicts with the
# commands \{ and \} for these it is advised to use the version @{ and @} or use
# a double escape (\\{ and \\})
ALIASES =
# This tag can be used to specify a number of word-keyword mappings (TCL only).
# A mapping has the form "name=value". For example adding "class=itcl::class"
# will allow you to use the command class in the itcl::class meaning.
TCL_SUBST =
# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources
# only. Doxygen will then generate output that is more tailored for C. For
# instance, some of the names that are used will be different. The list of all
@ -264,28 +289,40 @@ OPTIMIZE_FOR_FORTRAN = NO
OPTIMIZE_OUTPUT_VHDL = NO
# Set the OPTIMIZE_OUTPUT_SLICE tag to YES if your project consists of Slice
# sources only. Doxygen will then generate output that is more tailored for that
# language. For instance, namespaces will be presented as modules, types will be
# separated into more groups, etc.
# The default value is: NO.
OPTIMIZE_OUTPUT_SLICE = NO
# Doxygen selects the parser to use depending on the extension of the files it
# parses. With this tag you can assign which parser to use for a given
# extension. Doxygen has a built-in mapping, but you can override or extend it
# using this tag. The format is ext=language, where ext is a file extension, and
# language is one of the parsers supported by doxygen: IDL, Java, Javascript,
# C#, C, C++, D, PHP, Objective-C, Python, Fortran (fixed format Fortran:
# FortranFixed, free formatted Fortran: FortranFree, unknown formatted Fortran:
# Fortran. In the later case the parser tries to guess whether the code is fixed
# or free formatted code, this is the default for Fortran type files), VHDL. For
# instance to make doxygen treat .inc files as Fortran files (default is PHP),
# and .f files as C (default is Fortran), use: inc=Fortran f=C.
# language is one of the parsers supported by doxygen: IDL, Java, JavaScript,
# Csharp (C#), C, C++, D, PHP, md (Markdown), Objective-C, Python, Slice, VHDL,
# Fortran (fixed format Fortran: FortranFixed, free formatted Fortran:
# FortranFree, unknown formatted Fortran: Fortran. In the later case the parser
# tries to guess whether the code is fixed or free formatted code, this is the
# default for Fortran type files). For instance to make doxygen treat .inc files
# as Fortran files (default is PHP), and .f files as C (default is Fortran),
# use: inc=Fortran f=C.
#
# Note: For files without extension you can use no_extension as a placeholder.
#
# Note that for custom extensions you also need to set FILE_PATTERNS otherwise
# the files are not read by doxygen.
# the files are not read by doxygen. When specifying no_extension you should add
# * to the FILE_PATTERNS.
#
# Note see also the list of default file extension mappings.
EXTENSION_MAPPING =
# If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments
# according to the Markdown format, which allows for more readable
# documentation. See http://daringfireball.net/projects/markdown/ for details.
# documentation. See https://daringfireball.net/projects/markdown/ for details.
# The output of markdown processing is further processed by doxygen, so you can
# mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in
# case of backward compatibilities issues.
@ -293,6 +330,15 @@ EXTENSION_MAPPING =
MARKDOWN_SUPPORT = YES
# When the TOC_INCLUDE_HEADINGS tag is set to a non-zero value, all headings up
# to that level are automatically included in the table of contents, even if
# they do not have an id attribute.
# Note: This feature currently applies only to Markdown headings.
# Minimum value: 0, maximum value: 99, default value: 5.
# This tag requires that the tag MARKDOWN_SUPPORT is set to YES.
TOC_INCLUDE_HEADINGS = 5
# When enabled doxygen tries to link words that correspond to documented
# classes, or namespaces to their corresponding documentation. Such a link can
# be prevented in individual cases by putting a % sign in front of the word or
@ -318,7 +364,7 @@ BUILTIN_STL_SUPPORT = NO
CPP_CLI_SUPPORT = NO
# Set the SIP_SUPPORT tag to YES if your project consists of sip (see:
# http://www.riverbankcomputing.co.uk/software/sip/intro) sources only. Doxygen
# https://www.riverbankcomputing.com/software/sip/intro) sources only. Doxygen
# will parse them like normal C++ but will assume all classes use public instead
# of private inheritance when no explicit protection keyword is present.
# The default value is: NO.
@ -404,6 +450,19 @@ TYPEDEF_HIDES_STRUCT = NO
LOOKUP_CACHE_SIZE = 0
# The NUM_PROC_THREADS specifies the number threads doxygen is allowed to use
# during processing. When set to 0 doxygen will based this on the number of
# cores available in the system. You can set it explicitly to a value larger
# than 0 to get more control over the balance between CPU load and processing
# speed. At this moment only the input processing can be done using multiple
# threads. Since this is still an experimental feature the default is set to 1,
# which efficively disables parallel processing. Please report any issues you
# encounter. Generating dot graphs in parallel is controlled by the
# DOT_NUM_THREADS setting.
# Minimum value: 0, maximum value: 32, default value: 1.
NUM_PROC_THREADS = 1
#---------------------------------------------------------------------------
# Build related configuration options
#---------------------------------------------------------------------------
@ -416,7 +475,7 @@ LOOKUP_CACHE_SIZE = 0
# normally produced when WARNINGS is set to YES.
# The default value is: NO.
EXTRACT_ALL =
EXTRACT_ALL = NO
# If the EXTRACT_PRIVATE tag is set to YES, all private members of a class will
# be included in the documentation.
@ -424,6 +483,12 @@ EXTRACT_ALL =
EXTRACT_PRIVATE = NO
# If the EXTRACT_PRIV_VIRTUAL tag is set to YES, documented private virtual
# methods of a class will be included in the documentation.
# The default value is: NO.
EXTRACT_PRIV_VIRTUAL = NO
# If the EXTRACT_PACKAGE tag is set to YES, all members with package or internal
# scope will be included in the documentation.
# The default value is: NO.
@ -461,6 +526,13 @@ EXTRACT_LOCAL_METHODS = NO
EXTRACT_ANON_NSPACES = NO
# If this flag is set to YES, the name of an unnamed parameter in a declaration
# will be determined by the corresponding definition. By default unnamed
# parameters remain unnamed in the output.
# The default value is: YES.
RESOLVE_UNNAMED_PARAMS = YES
# If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all
# undocumented members inside documented classes or files. If set to NO these
# members will be included in the various overviews, but no documentation
@ -478,8 +550,8 @@ HIDE_UNDOC_MEMBERS = NO
HIDE_UNDOC_CLASSES = NO
# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend
# (class|struct|union) declarations. If set to NO, these declarations will be
# included in the documentation.
# declarations. If set to NO, these declarations will be included in the
# documentation.
# The default value is: NO.
HIDE_FRIEND_COMPOUNDS = NO
@ -498,11 +570,18 @@ HIDE_IN_BODY_DOCS = NO
INTERNAL_DOCS = NO
# If the CASE_SENSE_NAMES tag is set to NO then doxygen will only generate file
# names in lower-case letters. If set to YES, upper-case letters are also
# allowed. This is useful if you have classes or files whose names only differ
# in case and if your file system supports case sensitive file names. Windows
# and Mac users are advised to set this option to NO.
# With the correct setting of option CASE_SENSE_NAMES doxygen will better be
# able to match the capabilities of the underlying filesystem. In case the
# filesystem is case sensitive (i.e. it supports files in the same directory
# whose names only differ in casing), the option must be set to YES to properly
# deal with such files in case they appear in the input. For filesystems that
# are not case sensitive the option should be be set to NO to properly deal with
# output files written for symbols that only differ in casing, such as for two
# classes, one named CLASS and the other named Class, and to also support
# references to files without having to specify the exact matching casing. On
# Windows (including Cygwin) and MacOS, users should typically set this option
# to NO, whereas on Linux or other Unix flavors it should typically be set to
# YES.
# The default value is: system dependent.
CASE_SENSE_NAMES = YES
@ -689,7 +768,7 @@ LAYOUT_FILE =
# The CITE_BIB_FILES tag can be used to specify one or more bib files containing
# the reference definitions. This must be a list of .bib files. The .bib
# extension is automatically appended if omitted. This requires the bibtex tool
# to be installed. See also http://en.wikipedia.org/wiki/BibTeX for more info.
# to be installed. See also https://en.wikipedia.org/wiki/BibTeX for more info.
# For LaTeX the style of the bibliography can be controlled using
# LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the
# search path. See also \cite for info how to create references.
@ -734,13 +813,17 @@ WARN_IF_DOC_ERROR = YES
# This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that
# are documented, but have no documentation for their parameters or return
# value. If set to NO, doxygen will only warn about wrong or incomplete
# parameter documentation, but not about the absence of documentation.
# parameter documentation, but not about the absence of documentation. If
# EXTRACT_ALL is set to YES then this flag will automatically be disabled.
# The default value is: NO.
WARN_NO_PARAMDOC = NO
# If the WARN_AS_ERROR tag is set to YES then doxygen will immediately stop when
# a warning is encountered.
# a warning is encountered. If the WARN_AS_ERROR tag is set to FAIL_ON_WARNINGS
# then doxygen will continue running as if WARN_AS_ERROR tag is set to NO, but
# at the end of the doxygen process doxygen will return with a non-zero status.
# Possible values are: NO, YES and FAIL_ON_WARNINGS.
# The default value is: NO.
WARN_AS_ERROR = NO
@ -776,8 +859,8 @@ INPUT =
# This tag can be used to specify the character encoding of the source files
# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
# libiconv (or the iconv built into libc) for the transcoding. See the libiconv
# documentation (see: http://www.gnu.org/software/libiconv) for the list of
# possible encodings.
# documentation (see:
# https://www.gnu.org/software/libiconv/) for the list of possible encodings.
# The default value is: UTF-8.
INPUT_ENCODING = UTF-8
@ -790,11 +873,15 @@ INPUT_ENCODING = UTF-8
# need to set EXTENSION_MAPPING for the extension otherwise the files are not
# read by doxygen.
#
# Note the list of default checked file patterns might differ from the list of
# default file extension mappings.
#
# If left blank the following patterns are tested:*.c, *.cc, *.cxx, *.cpp,
# *.c++, *.java, *.ii, *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h,
# *.hh, *.hxx, *.hpp, *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc,
# *.m, *.markdown, *.md, *.mm, *.dox, *.py, *.pyw, *.f90, *.f, *.for, *.tcl,
# *.vhd, *.vhdl, *.ucf, *.qsf, *.as and *.js.
# *.m, *.markdown, *.md, *.mm, *.dox (to be provided as doxygen C comment),
# *.py, *.pyw, *.f90, *.f95, *.f03, *.f08, *.f18, *.f, *.for, *.vhd, *.vhdl,
# *.ucf, *.qsf and *.ice.
FILE_PATTERNS =
@ -949,7 +1036,7 @@ INLINE_SOURCES = NO
STRIP_CODE_COMMENTS = YES
# If the REFERENCED_BY_RELATION tag is set to YES then for each documented
# function all documented functions referencing it will be listed.
# entity all documented functions referencing it will be listed.
# The default value is: NO.
REFERENCED_BY_RELATION = NO
@ -981,12 +1068,12 @@ SOURCE_TOOLTIPS = YES
# If the USE_HTAGS tag is set to YES then the references to source code will
# point to the HTML generated by the htags(1) tool instead of doxygen built-in
# source browser. The htags tool is part of GNU's global source tagging system
# (see http://www.gnu.org/software/global/global.html). You will need version
# (see https://www.gnu.org/software/global/global.html). You will need version
# 4.8.6 or higher.
#
# To use it do the following:
# - Install the latest version of global
# - Enable SOURCE_BROWSER and USE_HTAGS in the config file
# - Enable SOURCE_BROWSER and USE_HTAGS in the configuration file
# - Make sure the INPUT points to the root of the source tree
# - Run doxygen as normal
#
@ -1008,25 +1095,6 @@ USE_HTAGS = NO
VERBATIM_HEADERS = YES
# If the CLANG_ASSISTED_PARSING tag is set to YES then doxygen will use the
# clang parser (see: http://clang.llvm.org/) for more accurate parsing at the
# cost of reduced performance. This can be particularly helpful with template
# rich C++ code for which doxygen's built-in parser lacks the necessary type
# information.
# Note: The availability of this option depends on whether or not doxygen was
# generated with the -Duse-libclang=ON option for CMake.
# The default value is: NO.
CLANG_ASSISTED_PARSING = NO
# If clang assisted parsing is enabled you can provide the compiler with command
# line options that you would normally use when invoking the compiler. Note that
# the include paths will already be set by doxygen for the files and directories
# specified with INPUT and INCLUDE_PATH.
# This tag requires that the tag CLANG_ASSISTED_PARSING is set to YES.
CLANG_OPTIONS =
#---------------------------------------------------------------------------
# Configuration options related to the alphabetical class index
#---------------------------------------------------------------------------
@ -1038,13 +1106,6 @@ CLANG_OPTIONS =
ALPHABETICAL_INDEX = YES
# The COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns in
# which the alphabetical index list will be split.
# Minimum value: 1, maximum value: 20, default value: 5.
# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
COLS_IN_ALPHA_INDEX = 5
# In case all classes in a project start with a common prefix, all classes will
# be put under the same header in the alphabetical index. The IGNORE_PREFIX tag
# can be used to specify a prefix (or a list of prefixes) that should be ignored
@ -1145,7 +1206,7 @@ HTML_EXTRA_FILES =
# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen
# will adjust the colors in the style sheet and background images according to
# this color. Hue is specified as an angle on a colorwheel, see
# http://en.wikipedia.org/wiki/Hue for more information. For instance the value
# https://en.wikipedia.org/wiki/Hue for more information. For instance the value
# 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300
# purple, and 360 is red again.
# Minimum value: 0, maximum value: 359, default value: 220.
@ -1181,6 +1242,17 @@ HTML_COLORSTYLE_GAMMA = 80
HTML_TIMESTAMP = NO
# If the HTML_DYNAMIC_MENUS tag is set to YES then the generated HTML
# documentation will contain a main index with vertical navigation menus that
# are dynamically created via JavaScript. If disabled, the navigation index will
# consists of multiple levels of tabs that are statically embedded in every HTML
# page. Disable this option to support browsers that do not have JavaScript,
# like the Qt help browser.
# The default value is: YES.
# This tag requires that the tag GENERATE_HTML is set to YES.
HTML_DYNAMIC_MENUS = YES
# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML
# documentation will contain sections that can be hidden and shown after the
# page has loaded.
@ -1204,13 +1276,14 @@ HTML_INDEX_NUM_ENTRIES = 100
# If the GENERATE_DOCSET tag is set to YES, additional index files will be
# generated that can be used as input for Apple's Xcode 3 integrated development
# environment (see: http://developer.apple.com/tools/xcode/), introduced with
# OSX 10.5 (Leopard). To create a documentation set, doxygen will generate a
# Makefile in the HTML output directory. Running make will produce the docset in
# that directory and running make install will install the docset in
# environment (see:
# https://developer.apple.com/xcode/), introduced with OSX 10.5 (Leopard). To
# create a documentation set, doxygen will generate a Makefile in the HTML
# output directory. Running make will produce the docset in that directory and
# running make install will install the docset in
# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at
# startup. See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html
# for more information.
# startup. See https://developer.apple.com/library/archive/featuredarticles/Doxy
# genXcode/_index.html for more information.
# The default value is: NO.
# This tag requires that the tag GENERATE_HTML is set to YES.
@ -1249,8 +1322,8 @@ DOCSET_PUBLISHER_NAME = Publisher
# If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three
# additional HTML index files: index.hhp, index.hhc, and index.hhk. The
# index.hhp is a project file that can be read by Microsoft's HTML Help Workshop
# (see: http://www.microsoft.com/en-us/download/details.aspx?id=21138) on
# Windows.
# (see:
# https://www.microsoft.com/en-us/download/details.aspx?id=21138) on Windows.
#
# The HTML Help Workshop contains a compiler that can convert all HTML output
# generated by doxygen into a single compiled HTML file (.chm). Compiled HTML
@ -1280,7 +1353,7 @@ CHM_FILE =
HHC_LOCATION =
# The GENERATE_CHI flag controls if a separate .chi index file is generated
# (YES) or that it should be included in the master .chm file (NO).
# (YES) or that it should be included in the main .chm file (NO).
# The default value is: NO.
# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
@ -1325,7 +1398,8 @@ QCH_FILE =
# The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help
# Project output. For more information please see Qt Help Project / Namespace
# (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#namespace).
# (see:
# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#namespace).
# The default value is: org.doxygen.Project.
# This tag requires that the tag GENERATE_QHP is set to YES.
@ -1333,8 +1407,8 @@ QHP_NAMESPACE = org.doxygen.Project
# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt
# Help Project output. For more information please see Qt Help Project / Virtual
# Folders (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#virtual-
# folders).
# Folders (see:
# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#virtual-folders).
# The default value is: doc.
# This tag requires that the tag GENERATE_QHP is set to YES.
@ -1342,30 +1416,30 @@ QHP_VIRTUAL_FOLDER = doc
# If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom
# filter to add. For more information please see Qt Help Project / Custom
# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom-
# filters).
# Filters (see:
# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom-filters).
# This tag requires that the tag GENERATE_QHP is set to YES.
QHP_CUST_FILTER_NAME =
# The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the
# custom filter to add. For more information please see Qt Help Project / Custom
# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom-
# filters).
# Filters (see:
# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom-filters).
# This tag requires that the tag GENERATE_QHP is set to YES.
QHP_CUST_FILTER_ATTRS =
# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this
# project's filter section matches. Qt Help Project / Filter Attributes (see:
# http://qt-project.org/doc/qt-4.8/qthelpproject.html#filter-attributes).
# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#filter-attributes).
# This tag requires that the tag GENERATE_QHP is set to YES.
QHP_SECT_FILTER_ATTRS =
# The QHG_LOCATION tag can be used to specify the location of Qt's
# qhelpgenerator. If non-empty doxygen will try to run qhelpgenerator on the
# generated .qhp file.
# The QHG_LOCATION tag can be used to specify the location (absolute path
# including file name) of Qt's qhelpgenerator. If non-empty doxygen will try to
# run qhelpgenerator on the generated .qhp file.
# This tag requires that the tag GENERATE_QHP is set to YES.
QHG_LOCATION =
@ -1442,6 +1516,17 @@ TREEVIEW_WIDTH = 250
EXT_LINKS_IN_WINDOW = NO
# If the HTML_FORMULA_FORMAT option is set to svg, doxygen will use the pdf2svg
# tool (see https://github.com/dawbarton/pdf2svg) or inkscape (see
# https://inkscape.org) to generate formulas as SVG images instead of PNGs for
# the HTML output. These images will generally look nicer at scaled resolutions.
# Possible values are: png (the default) and svg (looks nicer but requires the
# pdf2svg or inkscape tool).
# The default value is: png.
# This tag requires that the tag GENERATE_HTML is set to YES.
HTML_FORMULA_FORMAT = png
# Use this tag to change the font size of LaTeX formulas included as images in
# the HTML documentation. When you change the font size after a successful
# doxygen run you need to manually remove any form_*.png images from the HTML
@ -1451,7 +1536,7 @@ EXT_LINKS_IN_WINDOW = NO
FORMULA_FONTSIZE = 10
# Use the FORMULA_TRANPARENT tag to determine whether or not the images
# Use the FORMULA_TRANSPARENT tag to determine whether or not the images
# generated for formulas are transparent PNGs. Transparent PNGs are not
# supported properly for IE 6.0, but are supported on all modern browsers.
#
@ -1462,8 +1547,14 @@ FORMULA_FONTSIZE = 10
FORMULA_TRANSPARENT = YES
# The FORMULA_MACROFILE can contain LaTeX \newcommand and \renewcommand commands
# to create new LaTeX commands to be used in formulas as building blocks. See
# the section "Including formulas" for details.
FORMULA_MACROFILE =
# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see
# http://www.mathjax.org) which uses client side Javascript for the rendering
# https://www.mathjax.org) which uses client side JavaScript for the rendering
# instead of using pre-rendered bitmaps. Use this if you do not have LaTeX
# installed or if you want to formulas look prettier in the HTML output. When
# enabled you may also need to install MathJax separately and configure the path
@ -1475,7 +1566,7 @@ USE_MATHJAX = NO
# When MathJax is enabled you can set the default output format to be used for
# the MathJax output. See the MathJax site (see:
# http://docs.mathjax.org/en/latest/output.html) for more details.
# http://docs.mathjax.org/en/v2.7-latest/output.html) for more details.
# Possible values are: HTML-CSS (which is slower, but has the best
# compatibility), NativeMML (i.e. MathML) and SVG.
# The default value is: HTML-CSS.
@ -1490,8 +1581,8 @@ MATHJAX_FORMAT = HTML-CSS
# MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax
# Content Delivery Network so you can quickly see the result without installing
# MathJax. However, it is strongly recommended to install a local copy of
# MathJax from http://www.mathjax.org before deployment.
# The default value is: http://cdn.mathjax.org/mathjax/latest.
# MathJax from https://www.mathjax.org before deployment.
# The default value is: https://cdn.jsdelivr.net/npm/mathjax@2.
# This tag requires that the tag USE_MATHJAX is set to YES.
MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest
@ -1505,7 +1596,8 @@ MATHJAX_EXTENSIONS =
# The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces
# of code that will be used on startup of the MathJax code. See the MathJax site
# (see: http://docs.mathjax.org/en/latest/output.html) for more details. For an
# (see:
# http://docs.mathjax.org/en/v2.7-latest/output.html) for more details. For an
# example see the documentation.
# This tag requires that the tag USE_MATHJAX is set to YES.
@ -1533,7 +1625,7 @@ MATHJAX_CODEFILE =
SEARCHENGINE = YES
# When the SERVER_BASED_SEARCH tag is enabled the search engine will be
# implemented using a web server instead of a web client using Javascript. There
# implemented using a web server instead of a web client using JavaScript. There
# are two flavors of web server based searching depending on the EXTERNAL_SEARCH
# setting. When disabled, doxygen will generate a PHP script for searching and
# an index file used by the script. When EXTERNAL_SEARCH is enabled the indexing
@ -1552,7 +1644,8 @@ SERVER_BASED_SEARCH = NO
#
# Doxygen ships with an example indexer (doxyindexer) and search engine
# (doxysearch.cgi) which are based on the open source search engine library
# Xapian (see: http://xapian.org/).
# Xapian (see:
# https://xapian.org/).
#
# See the section "External Indexing and Searching" for details.
# The default value is: NO.
@ -1565,8 +1658,9 @@ EXTERNAL_SEARCH = NO
#
# Doxygen ships with an example indexer (doxyindexer) and search engine
# (doxysearch.cgi) which are based on the open source search engine library
# Xapian (see: http://xapian.org/). See the section "External Indexing and
# Searching" for details.
# Xapian (see:
# https://xapian.org/). See the section "External Indexing and Searching" for
# details.
# This tag requires that the tag SEARCHENGINE is set to YES.
SEARCHENGINE_URL =
@ -1617,21 +1711,35 @@ LATEX_OUTPUT = latex
# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
# invoked.
#
# Note that when enabling USE_PDFLATEX this option is only used for generating
# bitmaps for formulas in the HTML output, but not in the Makefile that is
# written to the output directory.
# The default file is: latex.
# Note that when not enabling USE_PDFLATEX the default is latex when enabling
# USE_PDFLATEX the default is pdflatex and when in the later case latex is
# chosen this is overwritten by pdflatex. For specific output languages the
# default can have been set differently, this depends on the implementation of
# the output language.
# This tag requires that the tag GENERATE_LATEX is set to YES.
LATEX_CMD_NAME = latex
# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to generate
# index for LaTeX.
# Note: This tag is used in the Makefile / make.bat.
# See also: LATEX_MAKEINDEX_CMD for the part in the generated output file
# (.tex).
# The default file is: makeindex.
# This tag requires that the tag GENERATE_LATEX is set to YES.
MAKEINDEX_CMD_NAME = makeindex
# The LATEX_MAKEINDEX_CMD tag can be used to specify the command name to
# generate index for LaTeX. In case there is no backslash (\) as first character
# it will be automatically added in the LaTeX code.
# Note: This tag is used in the generated output file (.tex).
# See also: MAKEINDEX_CMD_NAME for the part in the Makefile / make.bat.
# The default value is: makeindex.
# This tag requires that the tag GENERATE_LATEX is set to YES.
LATEX_MAKEINDEX_CMD = makeindex
# If the COMPACT_LATEX tag is set to YES, doxygen generates more compact LaTeX
# documents. This may be useful for small projects and may help to save some
# trees in general.
@ -1716,9 +1824,11 @@ LATEX_EXTRA_FILES =
PDF_HYPERLINKS = YES
# If the USE_PDFLATEX tag is set to YES, doxygen will use pdflatex to generate
# the PDF file directly from the LaTeX files. Set this option to YES, to get a
# higher quality PDF documentation.
# If the USE_PDFLATEX tag is set to YES, doxygen will use the engine as
# specified with LATEX_CMD_NAME to generate the PDF file directly from the LaTeX
# files. Set this option to YES, to get a higher quality PDF documentation.
#
# See also section LATEX_CMD_NAME for selecting the engine.
# The default value is: YES.
# This tag requires that the tag GENERATE_LATEX is set to YES.
@ -1752,7 +1862,7 @@ LATEX_SOURCE_CODE = NO
# The LATEX_BIB_STYLE tag can be used to specify the style to use for the
# bibliography, e.g. plainnat, or ieeetr. See
# http://en.wikipedia.org/wiki/BibTeX and \cite for more info.
# https://en.wikipedia.org/wiki/BibTeX and \cite for more info.
# The default value is: plain.
# This tag requires that the tag GENERATE_LATEX is set to YES.
@ -1766,6 +1876,14 @@ LATEX_BIB_STYLE = plain
LATEX_TIMESTAMP = NO
# The LATEX_EMOJI_DIRECTORY tag is used to specify the (relative or absolute)
# path from which the emoji images will be read. If a relative path is entered,
# it will be relative to the LATEX_OUTPUT directory. If left blank the
# LATEX_OUTPUT directory will be used.
# This tag requires that the tag GENERATE_LATEX is set to YES.
LATEX_EMOJI_DIRECTORY =
#---------------------------------------------------------------------------
# Configuration options related to the RTF output
#---------------------------------------------------------------------------
@ -1805,9 +1923,9 @@ COMPACT_RTF = NO
RTF_HYPERLINKS = NO
# Load stylesheet definitions from file. Syntax is similar to doxygen's config
# file, i.e. a series of assignments. You only have to provide replacements,
# missing definitions are set to their default value.
# Load stylesheet definitions from file. Syntax is similar to doxygen's
# configuration file, i.e. a series of assignments. You only have to provide
# replacements, missing definitions are set to their default value.
#
# See also section "Doxygen usage" for information on how to generate the
# default style sheet that doxygen normally uses.
@ -1816,8 +1934,8 @@ RTF_HYPERLINKS = NO
RTF_STYLESHEET_FILE =
# Set optional variables used in the generation of an RTF document. Syntax is
# similar to doxygen's config file. A template extensions file can be generated
# using doxygen -e rtf extensionFile.
# similar to doxygen's configuration file. A template extensions file can be
# generated using doxygen -e rtf extensionFile.
# This tag requires that the tag GENERATE_RTF is set to YES.
RTF_EXTENSIONS_FILE =
@ -1903,6 +2021,13 @@ XML_OUTPUT = xml
XML_PROGRAMLISTING = YES
# If the XML_NS_MEMB_FILE_SCOPE tag is set to YES, doxygen will include
# namespace members in file scope as well, matching the HTML output.
# The default value is: NO.
# This tag requires that the tag GENERATE_XML is set to YES.
XML_NS_MEMB_FILE_SCOPE = NO
#---------------------------------------------------------------------------
# Configuration options related to the DOCBOOK output
#---------------------------------------------------------------------------
@ -1935,9 +2060,9 @@ DOCBOOK_PROGRAMLISTING = NO
#---------------------------------------------------------------------------
# If the GENERATE_AUTOGEN_DEF tag is set to YES, doxygen will generate an
# AutoGen Definitions (see http://autogen.sf.net) file that captures the
# structure of the code including all documentation. Note that this feature is
# still experimental and incomplete at the moment.
# AutoGen Definitions (see http://autogen.sourceforge.net/) file that captures
# the structure of the code including all documentation. Note that this feature
# is still experimental and incomplete at the moment.
# The default value is: NO.
GENERATE_AUTOGEN_DEF = NO
@ -2104,12 +2229,6 @@ EXTERNAL_GROUPS = YES
EXTERNAL_PAGES = YES
# The PERL_PATH should be the absolute path and name of the perl script
# interpreter (i.e. the result of 'which perl').
# The default file (with absolute path) is: /usr/bin/perl.
PERL_PATH = /usr/bin/perl
#---------------------------------------------------------------------------
# Configuration options related to the dot tool
#---------------------------------------------------------------------------
@ -2123,15 +2242,6 @@ PERL_PATH = /usr/bin/perl
CLASS_DIAGRAMS = YES
# You can define message sequence charts within doxygen comments using the \msc
# command. Doxygen will then run the mscgen tool (see:
# http://www.mcternan.me.uk/mscgen/)) to produce the chart and insert it in the
# documentation. The MSCGEN_PATH tag allows you to specify the directory where
# the mscgen tool resides. If left empty the tool is assumed to be found in the
# default search path.
MSCGEN_PATH =
# You can include diagrams made with dia in doxygen documentation. Doxygen will
# then run dia to produce the diagram and insert it in the documentation. The
# DIA_PATH tag allows you to specify the directory where the dia binary resides.
@ -2150,7 +2260,7 @@ HIDE_UNDOC_RELATIONS = YES
# http://www.graphviz.org/), a graph visualization toolkit from AT&T and Lucent
# Bell Labs. The other options in this section have no effect if this option is
# set to NO
# The default value is: YES.
# The default value is: NO.
HAVE_DOT = YES
@ -2229,10 +2339,32 @@ UML_LOOK = NO
# but if the number exceeds 15, the total amount of fields shown is limited to
# 10.
# Minimum value: 0, maximum value: 100, default value: 10.
# This tag requires that the tag HAVE_DOT is set to YES.
# This tag requires that the tag UML_LOOK is set to YES.
UML_LIMIT_NUM_FIELDS = 10
# If the DOT_UML_DETAILS tag is set to NO, doxygen will show attributes and
# methods without types and arguments in the UML graphs. If the DOT_UML_DETAILS
# tag is set to YES, doxygen will add type and arguments for attributes and
# methods in the UML graphs. If the DOT_UML_DETAILS tag is set to NONE, doxygen
# will not generate fields with class member information in the UML graphs. The
# class diagrams will look similar to the default class diagrams but using UML
# notation for the relationships.
# Possible values are: NO, YES and NONE.
# The default value is: NO.
# This tag requires that the tag UML_LOOK is set to YES.
DOT_UML_DETAILS = NO
# The DOT_WRAP_THRESHOLD tag can be used to set the maximum number of characters
# to display on a single line. If the actual line length exceeds this threshold
# significantly it will wrapped across multiple lines. Some heuristics are apply
# to avoid ugly line breaks.
# Minimum value: 0, maximum value: 1000, default value: 17.
# This tag requires that the tag HAVE_DOT is set to YES.
DOT_WRAP_THRESHOLD = 17
# If the TEMPLATE_RELATIONS tag is set to YES then the inheritance and
# collaboration graphs will show the relations between templates and their
# instances.
@ -2306,9 +2438,7 @@ DIRECTORY_GRAPH = YES
# Note: If you choose svg you need to set HTML_FILE_EXTENSION to xhtml in order
# to make the SVG files visible in IE 9+ (other browsers do not have this
# requirement).
# Possible values are: png, png:cairo, png:cairo:cairo, png:cairo:gd, png:gd,
# png:gd:gd, jpg, jpg:cairo, jpg:cairo:gd, jpg:gd, jpg:gd:gd, gif, gif:cairo,
# gif:cairo:gd, gif:gd, gif:gd:gd, svg, png:gd, png:gd:gd, png:cairo,
# Possible values are: png, jpg, gif, svg, png:gd, png:gd:gd, png:cairo,
# png:cairo:gd, png:cairo:cairo, png:cairo:gdiplus, png:gdiplus and
# png:gdiplus:gdiplus.
# The default value is: png.
@ -2361,6 +2491,11 @@ DIAFILE_DIRS =
PLANTUML_JAR_PATH =
# When using plantuml, the PLANTUML_CFG_FILE tag can be used to specify a
# configuration file for plantuml.
PLANTUML_CFG_FILE =
# When using plantuml, the specified paths are searched for files specified by
# the !include statement in a plantuml block.
@ -2419,9 +2554,11 @@ DOT_MULTI_TARGETS = NO
GENERATE_LEGEND = YES
# If the DOT_CLEANUP tag is set to YES, doxygen will remove the intermediate dot
# If the DOT_CLEANUP tag is set to YES, doxygen will remove the intermediate
# files that are used to generate the various graphs.
#
# Note: This setting is not only used for dot files but also for msc and
# plantuml temporary files.
# The default value is: YES.
# This tag requires that the tag HAVE_DOT is set to YES.
DOT_CLEANUP = YES

View File

@ -4,7 +4,7 @@ import xml.etree.ElementTree as ET
from docs.docs import ClassDoc, Doc, Docs, FreeDoc
DOXYGEN_CONF = 'conf_doxygen.py'
DOXYGEN_CONF = 'doxygen.conf'
class ParseDoxygenXML():

View File

@ -4,7 +4,7 @@ from docs.doc_template import ClassDoc, Doc, Docs, FreeDoc
import os.path as path
import xml.etree.ElementTree as ET
DOXYGEN_CONF = 'conf_doxygen.py'
DOXYGEN_CONF = 'doxygen.conf'
def parse(input_path, output_path, quiet=False, generate_xml_flag=True):

View File

@ -12,11 +12,11 @@ Author: Duy Nguyen Ta, Fan Jiang, Matthew Sklar, Varun Agrawal, and Frank Dellae
# pylint: disable=unnecessary-lambda, unused-import, expression-not-assigned, no-else-return, protected-access, too-few-public-methods, too-many-arguments
import sys
import typing
from typing import Iterable, Union, Tuple, List
import pyparsing
import pyparsing # type: ignore
from pyparsing import (CharsNotIn, Forward, Group, Keyword, Literal, OneOrMore,
Optional, Or, ParseException, ParserElement, Suppress,
Optional, Or, ParseException, ParseResults, ParserElement, Suppress,
Word, ZeroOrMore, alphanums, alphas, cppStyleComment,
delimitedList, empty, nums, stringEnd)
@ -43,7 +43,8 @@ ParserElement.enablePackrat()
# rule for identifiers (e.g. variable names)
IDENT = Word(alphas + '_', alphanums + '_') ^ Word(nums)
POINTER, REF = map(Literal, "*&")
RAW_POINTER, SHARED_POINTER, REF = map(Literal, "@*&")
LPAREN, RPAREN, LBRACE, RBRACE, COLON, SEMI_COLON = map(Suppress, "(){}:;")
LOPBRACK, ROPBRACK, COMMA, EQUAL = map(Suppress, "<>,=")
CONST, VIRTUAL, CLASS, STATIC, PAIR, TEMPLATE, TYPEDEF, INCLUDE = map(
@ -71,36 +72,50 @@ BASIS_TYPES = map(
"size_t",
"double",
"float",
"string",
],
)
class Typename:
"""
Type's name with full namespaces, used in Type class.
Generic type which can be either a basic type or a class type,
similar to C++'s `typename` aka a qualified dependent type.
Contains type name with full namespace and template arguments.
E.g.
```
gtsam::PinholeCamera<gtsam::Cal3S2>
```
will give the name as `PinholeCamera`, namespace as `gtsam`,
and template instantiations as `[gtsam::Cal3S2]`.
Args:
namespaces_and_name: A list representing the namespaces of the type
with the type being the last element.
instantiations: Template parameters to the type.
"""
namespaces_name_rule = delimitedList(IDENT, "::")
instantiation_name_rule = delimitedList(IDENT, "::")
rule = Forward()
rule << (
namespaces_name_rule("namespaces_name")
namespaces_name_rule("namespaces_and_name") #
+ Optional(
(LOPBRACK + delimitedList(rule, ",")("instantiations") + ROPBRACK)
)
).setParseAction(lambda t: Typename(t.namespaces_name, t.instantiations))
(LOPBRACK + delimitedList(rule, ",")("instantiations") + ROPBRACK))
).setParseAction(lambda t: Typename(t.namespaces_and_name, t.instantiations))
def __init__(self, namespaces_name, instantiations=()):
self.namespaces = namespaces_name[:-1]
self.name = namespaces_name[-1]
def __init__(self,
namespaces_and_name: ParseResults,
instantiations: Union[tuple, list, str, ParseResults] = ()):
self.name = namespaces_and_name[-1] # the name is the last element in this list
self.namespaces = namespaces_and_name[:-1]
if instantiations:
if not isinstance(instantiations, typing.Iterable):
self.instantiations = instantiations.asList()
if isinstance(instantiations, Iterable):
self.instantiations = instantiations # type: ignore
else:
self.instantiations = instantiations
self.instantiations = instantiations.asList()
else:
self.instantiations = []
@ -108,21 +123,21 @@ class Typename:
self.namespaces = ["gtsam"]
@staticmethod
def from_parse_result(parse_result):
"""Return the typename from the parsed result."""
def from_parse_result(parse_result: Union[str, list]):
"""Unpack the parsed result to get the Typename instance."""
return parse_result[0]
def __repr__(self):
def __repr__(self) -> str:
return self.to_cpp()
def instantiated_name(self):
def instantiated_name(self) -> str:
"""Get the instantiated name of the type."""
res = self.name
for instantiation in self.instantiations:
res += instantiation.instantiated_name()
return res
def to_cpp(self):
def to_cpp(self) -> str:
"""Generate the C++ code for wrapping."""
idx = 1 if self.namespaces and not self.namespaces[0] else 0
if self.instantiations:
@ -137,93 +152,111 @@ class Typename:
cpp_name,
)
def __eq__(self, other):
def __eq__(self, other) -> bool:
if isinstance(other, Typename):
return str(self) == str(other)
else:
return NotImplemented
return False
def __ne__(self, other):
def __ne__(self, other) -> bool:
res = self.__eq__(other)
if res is NotImplemented:
return res
return not res
class Type:
"""
The type value that is parsed, e.g. void, string, size_t.
"""
class _QualifiedType:
"""
Type with qualifiers.
"""
class QualifiedType:
"""Type with qualifiers, such as `const`."""
rule = (
Optional(CONST("is_const"))
+ Typename.rule("typename")
+ Optional(POINTER("is_ptr") | REF("is_ref"))
Typename.rule("typename") #
+ Optional(SHARED_POINTER("is_shared_ptr") | RAW_POINTER("is_ptr") | REF("is_ref"))
).setParseAction(
lambda t: Type._QualifiedType(
Typename.from_parse_result(t.typename),
t.is_const,
t.is_ptr,
t.is_ref,
)
lambda t: QualifiedType(t)
)
def __init__(self, typename, is_const, is_ptr, is_ref):
self.typename = typename
self.is_const = is_const
self.is_ptr = is_ptr
self.is_ref = is_ref
def __init__(self, t: ParseResults):
self.typename = Typename.from_parse_result(t.typename)
self.is_shared_ptr = t.is_shared_ptr
self.is_ptr = t.is_ptr
self.is_ref = t.is_ref
class _BasisType:
"""
Basis types don't have qualifiers and only allow copy-by-value.
class BasisType:
"""
Basis types are the built-in types in C++ such as double, int, char, etc.
rule = Or(BASIS_TYPES).setParseAction(lambda t: Typename(t))
When using templates, the basis type will take on the same form as the template.
E.g.
```
template<T = {double}>
void func(const T& x);
```
will give
```
m_.def("CoolFunctionDoubleDouble",[](const double& s) {
return wrap_example::CoolFunction<double,double>(s);
}, py::arg("s"));
```
"""
rule = (
_BasisType.rule("basis") | _QualifiedType.rule("qualified") # BR
Or(BASIS_TYPES)("typename") #
+ Optional(SHARED_POINTER("is_shared_ptr") | RAW_POINTER("is_ptr") | REF("is_ref")) #
).setParseAction(lambda t: BasisType(t))
def __init__(self, t: ParseResults):
self.typename = Typename([t.typename])
self.is_ptr = t.is_ptr
self.is_shared_ptr = t.is_shared_ptr
self.is_ref = t.is_ref
class Type:
"""The type value that is parsed, e.g. void, string, size_t."""
rule = (
Optional(CONST("is_const")) #
+ (BasisType.rule("basis") | QualifiedType.rule("qualified")) # BR
).setParseAction(lambda t: Type.from_parse_result(t))
def __init__(self, typename, is_const, is_ptr, is_ref, is_basis):
def __init__(self, typename: Typename, is_const: str, is_shared_ptr: str,
is_ptr: str, is_ref: str, is_basis: bool):
self.typename = typename
self.is_const = is_const
self.is_shared_ptr = is_shared_ptr
self.is_ptr = is_ptr
self.is_ref = is_ref
self.is_basis = is_basis
@staticmethod
def from_parse_result(t):
def from_parse_result(t: ParseResults):
"""Return the resulting Type from parsing the source."""
if t.basis:
return Type(
typename=t.basis,
is_const='',
is_ptr='',
is_ref='',
typename=t.basis.typename,
is_const=t.is_const,
is_shared_ptr=t.basis.is_shared_ptr,
is_ptr=t.basis.is_ptr,
is_ref=t.basis.is_ref,
is_basis=True,
)
elif t.qualified:
return Type(
typename=t.qualified.typename,
is_const=t.qualified.is_const,
is_const=t.is_const,
is_shared_ptr=t.qualified.is_shared_ptr,
is_ptr=t.qualified.is_ptr,
is_ref=t.qualified.is_ref,
is_basis=False,
)
else:
raise ValueError("Parse result is not a Type?")
raise ValueError("Parse result is not a Type")
def __repr__(self):
return '{} {}{}{}'.format(
self.typename, self.is_const, self.is_ptr, self.is_ref
)
def __repr__(self) -> str:
return "{self.typename} " \
"{self.is_const}{self.is_shared_ptr}{self.is_ptr}{self.is_ref}".format(
self=self)
def to_cpp(self, use_boost):
def to_cpp(self, use_boost: bool) -> str:
"""
Generate the C++ code for wrapping.
@ -231,26 +264,24 @@ class Type:
Treat Matrix and Vector as "const Matrix&" and "const Vector&" resp.
"""
shared_ptr_ns = "boost" if use_boost else "std"
return (
"{const} {shared_ptr}{typename}"
"{shared_ptr_ropbracket}{ref}".format(
const="const"
if self.is_const
or self.is_ptr
or self.typename.name in ["Matrix", "Vector"]
else "",
typename=self.typename.to_cpp(),
shared_ptr="{}::shared_ptr<".format(shared_ptr_ns)
if self.is_ptr
else "",
shared_ptr_ropbracket=">" if self.is_ptr else "",
ref="&"
if self.is_ref
or self.is_ptr
or self.typename.name in ["Matrix", "Vector"]
else "",
)
)
if self.is_shared_ptr:
# always pass by reference: https://stackoverflow.com/a/8741626/1236990
typename = "{ns}::shared_ptr<{typename}>&".format(
ns=shared_ptr_ns, typename=self.typename.to_cpp())
elif self.is_ptr:
typename = "{typename}*".format(typename=self.typename.to_cpp())
elif self.is_ref or self.typename.name in ["Matrix", "Vector"]:
typename = typename = "{typename}&".format(
typename=self.typename.to_cpp())
else:
typename = self.typename.to_cpp()
return ("{const}{typename}".format(
const="const " if
(self.is_const
or self.typename.name in ["Matrix", "Vector"]) else "",
typename=typename))
class Argument:
@ -259,18 +290,18 @@ class Argument:
E.g.
```
void sayHello(/*s is the method argument with type `const string&`*/ const string& s);
void sayHello(/*`s` is the method argument with type `const string&`*/ const string& s);
```
"""
rule = (Type.rule("ctype") + IDENT("name")).setParseAction(
lambda t: Argument(t.ctype, t.name)
)
rule = (Type.rule("ctype") +
IDENT("name")).setParseAction(lambda t: Argument(t.ctype, t.name))
def __init__(self, ctype, name):
def __init__(self, ctype: Type, name: str):
self.ctype = ctype
self.name = name
self.parent: Union[ArgumentList, None] = None
def __repr__(self):
def __repr__(self) -> str:
return '{} {}'.format(self.ctype.__repr__(), self.name)
@ -282,27 +313,32 @@ class ArgumentList:
lambda t: ArgumentList.from_parse_result(t.args_list)
)
def __init__(self, args_list):
def __init__(self, args_list: List[Argument]):
self.args_list = args_list
for arg in args_list:
arg.parent = self
self.parent: Union[Method, StaticMethod, Template, Constructor,
GlobalFunction, None] = None
@staticmethod
def from_parse_result(parse_result):
def from_parse_result(parse_result: ParseResults):
"""Return the result of parsing."""
if parse_result:
return ArgumentList(parse_result.asList())
else:
return ArgumentList([])
def __repr__(self):
def __repr__(self) -> str:
return self.args_list.__repr__()
def args_names(self):
def __len__(self) -> int:
return len(self.args_list)
def args_names(self) -> List[str]:
"""Return a list of the names of all the arguments."""
return [arg.name for arg in self.args_list]
def to_cpp(self, use_boost):
def to_cpp(self, use_boost: bool) -> List[str]:
"""Generate the C++ code for wrapping."""
return [arg.ctype.to_cpp(use_boost) for arg in self.args_list]
@ -314,40 +350,44 @@ class ReturnType:
The return type can either be a single type or a pair such as <type1, type2>.
"""
_pair = (
PAIR.suppress()
+ LOPBRACK
+ Type.rule("type1")
+ COMMA
+ Type.rule("type2")
+ ROPBRACK
PAIR.suppress() #
+ LOPBRACK #
+ Type.rule("type1") #
+ COMMA #
+ Type.rule("type2") #
+ ROPBRACK #
)
rule = (_pair ^ Type.rule("type1")).setParseAction( # BR
lambda t: ReturnType(t.type1, t.type2)
)
lambda t: ReturnType(t.type1, t.type2))
def __init__(self, type1, type2):
def __init__(self, type1: Type, type2: Type):
self.type1 = type1
self.type2 = type2
self.parent: Union[Method, StaticMethod, GlobalFunction, None] = None
def is_void(self):
def is_void(self) -> bool:
"""
Check if the return type is void.
"""
return self.type1.typename.name == "void" and not self.type2
def __repr__(self):
def __repr__(self) -> str:
return "{}{}".format(
self.type1, (', ' + self.type2.__repr__()) if self.type2 else ''
)
self.type1, (', ' + self.type2.__repr__()) if self.type2 else '')
def to_cpp(self):
"""Generate the C++ code for wrapping."""
def to_cpp(self, use_boost: bool) -> str:
"""
Generate the C++ code for wrapping.
If there are two return types, we return a pair<>,
otherwise we return the regular return type.
"""
if self.type2:
return "std::pair<{type1},{type2}>".format(
type1=self.type1.to_cpp(), type2=self.type2.to_cpp()
)
type1=self.type1.to_cpp(use_boost),
type2=self.type2.to_cpp(use_boost))
else:
return self.type1.to_cpp()
return self.type1.to_cpp(use_boost)
class Template:
@ -365,20 +405,16 @@ class Template:
template<typename POSE> // POSE is the Instantiation.
"""
rule = (
IDENT("typename")
+ Optional(
EQUAL
+ LBRACE
+ ((delimitedList(Typename.rule)("instantiations")))
+ RBRACE
)
).setParseAction(
lambda t: Template.TypenameAndInstantiations(
t.typename, t.instantiations
)
)
IDENT("typename") #
+ Optional( #
EQUAL #
+ LBRACE #
+ ((delimitedList(Typename.rule)("instantiations"))) #
+ RBRACE #
)).setParseAction(lambda t: Template.TypenameAndInstantiations(
t.typename, t.instantiations))
def __init__(self, typename, instantiations):
def __init__(self, typename: str, instantiations: ParseResults):
self.typename = typename
if instantiations:
@ -387,22 +423,20 @@ class Template:
self.instantiations = []
rule = ( # BR
TEMPLATE
+ LOPBRACK
TEMPLATE #
+ LOPBRACK #
+ delimitedList(TypenameAndInstantiations.rule)(
"typename_and_instantiations_list"
)
"typename_and_instantiations_list") #
+ ROPBRACK # BR
).setParseAction(
lambda t: Template(t.typename_and_instantiations_list.asList())
)
lambda t: Template(t.typename_and_instantiations_list.asList()))
def __init__(self, typename_and_instantiations_list):
def __init__(self, typename_and_instantiations_list: List[TypenameAndInstantiations]):
ti_list = typename_and_instantiations_list
self.typenames = [ti.typename for ti in ti_list]
self.instantiations = [ti.instantiations for ti in ti_list]
def __repr__(self):
def __repr__(self) -> str:
return "<{0}>".format(", ".join(self.typenames))
@ -418,21 +452,24 @@ class Method:
```
"""
rule = (
Optional(Template.rule("template"))
+ ReturnType.rule("return_type")
+ IDENT("name")
+ LPAREN
+ ArgumentList.rule("args_list")
+ RPAREN
+ Optional(CONST("is_const"))
Optional(Template.rule("template")) #
+ ReturnType.rule("return_type") #
+ IDENT("name") #
+ LPAREN #
+ ArgumentList.rule("args_list") #
+ RPAREN #
+ Optional(CONST("is_const")) #
+ SEMI_COLON # BR
).setParseAction(
lambda t: Method(
t.template, t.name, t.return_type, t.args_list, t.is_const
)
)
).setParseAction(lambda t: Method(t.template, t.name, t.return_type, t.
args_list, t.is_const))
def __init__(self, template, name, return_type, args, is_const, parent=''):
def __init__(self,
template: str,
name: str,
return_type: ReturnType,
args: ArgumentList,
is_const: str,
parent: Union[str, "Class"] = ''):
self.template = template
self.name = name
self.return_type = return_type
@ -441,7 +478,7 @@ class Method:
self.parent = parent
def __repr__(self):
def __repr__(self) -> str:
return "Method: {} {} {}({}){}".format(
self.template,
self.return_type,
@ -463,28 +500,31 @@ class StaticMethod:
```
"""
rule = (
STATIC
+ ReturnType.rule("return_type")
+ IDENT("name")
+ LPAREN
+ ArgumentList.rule("args_list")
+ RPAREN
STATIC #
+ ReturnType.rule("return_type") #
+ IDENT("name") #
+ LPAREN #
+ ArgumentList.rule("args_list") #
+ RPAREN #
+ SEMI_COLON # BR
).setParseAction(
lambda t: StaticMethod(t.name, t.return_type, t.args_list)
)
lambda t: StaticMethod(t.name, t.return_type, t.args_list))
def __init__(self, name, return_type, args, parent=''):
def __init__(self,
name: str,
return_type: ReturnType,
args: ArgumentList,
parent: Union[str, "Class"] = ''):
self.name = name
self.return_type = return_type
self.args = args
self.parent = parent
def __repr__(self):
def __repr__(self) -> str:
return "static {} {}{}".format(self.return_type, self.name, self.args)
def to_cpp(self):
def to_cpp(self) -> str:
"""Generate the C++ code for wrapping."""
return self.name
@ -495,20 +535,20 @@ class Constructor:
Can have 0 or more arguments.
"""
rule = (
IDENT("name")
+ LPAREN
+ ArgumentList.rule("args_list")
+ RPAREN
IDENT("name") #
+ LPAREN #
+ ArgumentList.rule("args_list") #
+ RPAREN #
+ SEMI_COLON # BR
).setParseAction(lambda t: Constructor(t.name, t.args_list))
def __init__(self, name, args, parent=''):
def __init__(self, name: str, args: ArgumentList, parent: Union["Class", str] =''):
self.name = name
self.args = args
self.parent = parent
def __repr__(self):
def __repr__(self) -> str:
return "Constructor: {}".format(self.name)
@ -523,21 +563,28 @@ class Property:
};
````
"""
rule = (Type.rule("ctype") + IDENT("name") + SEMI_COLON).setParseAction(
lambda t: Property(t.ctype, t.name)
)
rule = (
Type.rule("ctype") #
+ IDENT("name") #
+ SEMI_COLON #
).setParseAction(lambda t: Property(t.ctype, t.name))
def __init__(self, ctype, name, parent=''):
def __init__(self, ctype: Type, name: str, parent=''):
self.ctype = ctype
self.name = name
self.parent = parent
def __repr__(self):
def __repr__(self) -> str:
return '{} {}'.format(self.ctype.__repr__(), self.name)
def collect_namespaces(obj):
"""Get the chain of namespaces from the lowest to highest for the given object."""
"""
Get the chain of namespaces from the lowest to highest for the given object.
Args:
obj: Object of type Namespace, Class or InstantiatedClass.
"""
namespaces = []
ancestor = obj.parent
while ancestor and ancestor.name:
@ -565,7 +612,8 @@ class Class:
Constructor.rule ^ StaticMethod.rule ^ Method.rule ^ Property.rule
).setParseAction(lambda t: Class.MethodsAndProperties(t.asList()))
def __init__(self, methods_props):
def __init__(self, methods_props: List[Union[Constructor, Method,
StaticMethod, Property]]):
self.ctors = []
self.methods = []
self.static_methods = []
@ -582,17 +630,16 @@ class Class:
_parent = COLON + Typename.rule("parent_class")
rule = (
Optional(Template.rule("template"))
+ Optional(VIRTUAL("is_virtual"))
+ CLASS
+ IDENT("name")
+ Optional(_parent)
+ LBRACE
+ MethodsAndProperties.rule("methods_props")
+ RBRACE
Optional(Template.rule("template")) #
+ Optional(VIRTUAL("is_virtual")) #
+ CLASS #
+ IDENT("name") #
+ Optional(_parent) #
+ LBRACE #
+ MethodsAndProperties.rule("methods_props") #
+ RBRACE #
+ SEMI_COLON # BR
).setParseAction(
lambda t: Class(
).setParseAction(lambda t: Class(
t.template,
t.is_virtual,
t.name,
@ -601,20 +648,19 @@ class Class:
t.methods_props.methods,
t.methods_props.static_methods,
t.methods_props.properties,
)
)
))
def __init__(
self,
template,
is_virtual,
name,
parent_class,
ctors,
methods,
static_methods,
properties,
parent='',
template: Template,
is_virtual: str,
name: str,
parent_class: list,
ctors: List[Constructor],
methods: List[Method],
static_methods: List[StaticMethod],
properties: List[Property],
parent: str = '',
):
self.template = template
self.is_virtual = is_virtual
@ -647,10 +693,13 @@ class Class:
for _property in self.properties:
_property.parent = self
def namespaces(self):
def namespaces(self) -> list:
"""Get the namespaces which this class is nested under as a list."""
return collect_namespaces(self)
def __repr__(self):
return "Class: {self.name}".format(self=self)
class TypedefTemplateInstantiation:
"""
@ -669,7 +718,7 @@ class TypedefTemplateInstantiation:
)
)
def __init__(self, typename, new_name, parent=''):
def __init__(self, typename: Typename, new_name: str, parent: str=''):
self.typename = typename
self.new_name = new_name
self.parent = parent
@ -683,11 +732,11 @@ class Include:
INCLUDE + LOPBRACK + CharsNotIn('>')("header") + ROPBRACK
).setParseAction(lambda t: Include(t.header))
def __init__(self, header, parent=''):
def __init__(self, header: CharsNotIn, parent: str = ''):
self.header = header
self.parent = parent
def __repr__(self):
def __repr__(self) -> str:
return "#include <{}>".format(self.header)
@ -702,22 +751,26 @@ class ForwardDeclaration:
+ Optional(COLON + Typename.rule("parent_type"))
+ SEMI_COLON
).setParseAction(
lambda t: ForwardDeclaration(t.is_virtual, t.name, t.parent_type)
lambda t: ForwardDeclaration(t.name, t.parent_type, t.is_virtual)
)
def __init__(self, is_virtual, name, parent_type, parent=''):
self.is_virtual = is_virtual
def __init__(self,
name: Typename,
parent_type: str,
is_virtual: str,
parent: str = ''):
self.name = name
if parent_type:
self.parent_type = Typename.from_parse_result(parent_type)
else:
self.parent_type = ''
self.is_virtual = is_virtual
self.parent = parent
def __repr__(self):
return "ForwardDeclaration: {} {}({})".format(
self.is_virtual, self.name, self.parent
)
def __repr__(self) -> str:
return "ForwardDeclaration: {} {}({})".format(self.is_virtual,
self.name, self.parent)
class GlobalFunction:
@ -725,37 +778,43 @@ class GlobalFunction:
Rule to parse functions defined in the global scope.
"""
rule = (
ReturnType.rule("return_type")
+ IDENT("name")
+ LPAREN
+ ArgumentList.rule("args_list")
+ RPAREN
+ SEMI_COLON
).setParseAction(
lambda t: GlobalFunction(t.name, t.return_type, t.args_list)
)
Optional(Template.rule("template"))
+ ReturnType.rule("return_type") #
+ IDENT("name") #
+ LPAREN #
+ ArgumentList.rule("args_list") #
+ RPAREN #
+ SEMI_COLON #
).setParseAction(lambda t: GlobalFunction(t.name, t.return_type, t.
args_list, t.template))
def __init__(self, name, return_type, args_list, parent=''):
def __init__(self,
name: str,
return_type: ReturnType,
args_list: ArgumentList,
template: Template,
parent: str = ''):
self.name = name
self.return_type = return_type
self.args = args_list
self.is_const = None
self.template = template
self.parent = parent
self.return_type.parent = self
self.args.parent = self
def __repr__(self):
def __repr__(self) -> str:
return "GlobalFunction: {}{}({})".format(
self.return_type, self.name, self.args
)
def to_cpp(self):
def to_cpp(self) -> str:
"""Generate the C++ code for wrapping."""
return self.name
def find_sub_namespace(namespace, str_namespaces):
def find_sub_namespace(namespace: "Namespace",
str_namespaces: List["Namespace"]) -> list:
"""
Get the namespaces nested under `namespace`, filtered by a list of namespace strings.
@ -774,7 +833,7 @@ def find_sub_namespace(namespace, str_namespaces):
ns for ns in sub_namespaces if ns.name == str_namespaces[0]
]
if not found_namespaces:
return None
return []
res = []
for found_namespace in found_namespaces:
@ -786,25 +845,24 @@ def find_sub_namespace(namespace, str_namespaces):
class Namespace:
"""Rule for parsing a namespace in the interface file."""
rule = Forward()
rule << (
NAMESPACE
+ IDENT("name")
+ LBRACE
NAMESPACE #
+ IDENT("name") #
+ LBRACE #
+ ZeroOrMore( # BR
ForwardDeclaration.rule
^ Include.rule
^ Class.rule
^ TypedefTemplateInstantiation.rule
^ GlobalFunction.rule
^ rule
)(
"content"
) # BR
+ RBRACE
ForwardDeclaration.rule #
^ Include.rule #
^ Class.rule #
^ TypedefTemplateInstantiation.rule #
^ GlobalFunction.rule #
^ rule #
)("content") # BR
+ RBRACE #
).setParseAction(lambda t: Namespace.from_parse_result(t))
def __init__(self, name, content, parent=''):
def __init__(self, name: str, content: ZeroOrMore, parent=''):
self.name = name
self.content = content
self.parent = parent
@ -812,7 +870,7 @@ class Namespace:
child.parent = self
@staticmethod
def from_parse_result(t):
def from_parse_result(t: ParseResults):
"""Return the result of parsing."""
if t.content:
content = t.content.asList()
@ -820,16 +878,18 @@ class Namespace:
content = []
return Namespace(t.name, content)
def find_class(self, typename):
def find_class_or_function(
self, typename: Typename) -> Union[Class, GlobalFunction]:
"""
Find the Class object given its typename.
Find the Class or GlobalFunction object given its typename.
We have to traverse the tree of namespaces.
"""
found_namespaces = find_sub_namespace(self, typename.namespaces)
res = []
for namespace in found_namespaces:
classes = (c for c in namespace.content if isinstance(c, Class))
res += [c for c in classes if c.name == typename.name]
classes_and_funcs = (c for c in namespace.content
if isinstance(c, (Class, GlobalFunction)))
res += [c for c in classes_and_funcs if c.name == typename.name]
if not res:
raise ValueError(
"Cannot find class {} in module!".format(typename.name)
@ -843,17 +903,17 @@ class Namespace:
else:
return res[0]
def top_level(self):
def top_level(self) -> "Namespace":
"""Return the top leve namespace."""
if self.name == '' or self.parent == '':
return self
else:
return self.parent.top_level()
def __repr__(self):
def __repr__(self) -> str:
return "Namespace: {}\n\t{}".format(self.name, self.content)
def full_namespaces(self):
def full_namespaces(self) -> List["Namespace"]:
"""Get the full namespace list."""
ancestors = collect_namespaces(self)
if self.name:
@ -874,20 +934,18 @@ class Module:
"""
rule = (
ZeroOrMore(
ForwardDeclaration.rule
^ Include.rule
^ Class.rule
^ TypedefTemplateInstantiation.rule
^ GlobalFunction.rule
^ Namespace.rule
).setParseAction(lambda t: Namespace('', t.asList()))
+ stringEnd
)
ZeroOrMore(ForwardDeclaration.rule #
^ Include.rule #
^ Class.rule #
^ TypedefTemplateInstantiation.rule #
^ GlobalFunction.rule #
^ Namespace.rule #
).setParseAction(lambda t: Namespace('', t.asList())) +
stringEnd)
rule.ignore(cppStyleComment)
@staticmethod
def parseString(s: str):
def parseString(s: str) -> ParseResults:
"""Parse the source string and apply the rules."""
return Module.rule.parseString(s)[0]

File diff suppressed because it is too large Load Diff

View File

@ -10,7 +10,7 @@ Code generator for wrapping a C++ module with Pybind11
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
# pylint: disable=too-many-arguments, too-many-instance-attributes, no-self-use, no-else-return, too-many-arguments, unused-format-string-argument, line-too-long
import re
import textwrap
@ -39,6 +39,9 @@ class PybindWrapper:
self.module_template = module_template
self.python_keywords = ['print', 'lambda']
# amount of indentation to add before each function/method declaration.
self.method_indent = '\n' + (' ' * 8)
def _py_args_names(self, args_list):
"""Set the argument names in Pybind11 format."""
names = args_list.args_names()
@ -60,7 +63,7 @@ class PybindWrapper:
"""Wrap the constructors."""
res = ""
for ctor in my_class.ctors:
res += ('\n' + ' ' * 8 + '.def(py::init<{args_cpp_types}>()'
res += (self.method_indent + '.def(py::init<{args_cpp_types}>()'
'{py_args_names})'.format(
args_cpp_types=", ".join(ctor.args.to_cpp(self.use_boost)),
py_args_names=self._py_args_names(ctor.args),
@ -74,32 +77,19 @@ class PybindWrapper:
if cpp_method in ["serialize", "serializable"]:
if not cpp_class in self._serializing_classes:
self._serializing_classes.append(cpp_class)
return textwrap.dedent('''
.def("serialize",
[]({class_inst} self){{
return gtsam::serialize(*self);
}}
)
.def("deserialize",
[]({class_inst} self, string serialized){{
gtsam::deserialize(serialized, *self);
}}, py::arg("serialized"))
'''.format(class_inst=cpp_class + '*'))
serialize_method = self.method_indent + \
".def(\"serialize\", []({class_inst} self){{ return gtsam::serialize(*self); }})".format(class_inst=cpp_class + '*')
deserialize_method = self.method_indent + \
".def(\"deserialize\", []({class_inst} self, string serialized){{ gtsam::deserialize(serialized, *self); }}, py::arg(\"serialized\"))" \
.format(class_inst=cpp_class + '*')
return serialize_method + deserialize_method
if cpp_method == "pickle":
if not cpp_class in self._serializing_classes:
raise ValueError("Cannot pickle a class which is not serializable")
return textwrap.dedent('''
.def(py::pickle(
[](const {cpp_class} &a){{ // __getstate__
/* Returns a string that encodes the state of the object */
return py::make_tuple(gtsam::serialize(a));
}},
[](py::tuple t){{ // __setstate__
{cpp_class} obj;
gtsam::deserialize(t[0].cast<std::string>(), obj);
return obj;
}}))
'''.format(cpp_class=cpp_class))
pickle_method = self.method_indent + \
".def(py::pickle({indent} [](const {cpp_class} &a){{ /* __getstate__: Returns a string that encodes the state of the object */ return py::make_tuple(gtsam::serialize(a)); }},{indent} [](py::tuple t){{ /* __setstate__ */ {cpp_class} obj; gtsam::deserialize(t[0].cast<std::string>(), obj); return obj; }}))"
return pickle_method.format(cpp_class=cpp_class, indent=self.method_indent)
is_method = isinstance(method, instantiator.InstantiatedMethod)
is_static = isinstance(method, parser.StaticMethod)
@ -128,14 +118,13 @@ class PybindWrapper:
else py_method + "_",
opt_self="{cpp_class}* self".format(
cpp_class=cpp_class) if is_method else "",
cpp_class=cpp_class,
cpp_method=cpp_method,
opt_comma=', ' if is_method and args_names else '',
args_signature_with_names=args_signature_with_names,
function_call=function_call,
py_args_names=py_args_names,
suffix=suffix,
))
if method.name == 'print':
type_list = method.args.to_cpp(self.use_boost)
if len(type_list) > 0 and type_list[0].strip() == 'string':
@ -163,7 +152,11 @@ class PybindWrapper:
return ret
def wrap_methods(self, methods, cpp_class, prefix='\n' + ' ' * 8, suffix=''):
"""Wrap all the methods in the `cpp_class`."""
"""
Wrap all the methods in the `cpp_class`.
This function is also used to wrap global functions.
"""
res = ""
for method in methods:
@ -185,6 +178,7 @@ class PybindWrapper:
prefix=prefix,
suffix=suffix,
)
return res
def wrap_properties(self, properties, cpp_class, prefix='\n' + ' ' * 8):
@ -325,7 +319,8 @@ class PybindWrapper:
# Global functions.
all_funcs = [
func for func in namespace.content
if isinstance(func, parser.GlobalFunction)
if isinstance(func, (parser.GlobalFunction,
instantiator.InstantiatedGlobalFunction))
]
wrapped += self.wrap_methods(
all_funcs,

View File

@ -45,6 +45,7 @@ def instantiate_type(ctype: parser.Type,
return parser.Type(
typename=instantiations[idx],
is_const=ctype.is_const,
is_shared_ptr=ctype.is_shared_ptr,
is_ptr=ctype.is_ptr,
is_ref=ctype.is_ref,
is_basis=ctype.is_basis,
@ -63,6 +64,7 @@ def instantiate_type(ctype: parser.Type,
return parser.Type(
typename=cpp_typename,
is_const=ctype.is_const,
is_shared_ptr=ctype.is_shared_ptr,
is_ptr=ctype.is_ptr,
is_ref=ctype.is_ref,
is_basis=ctype.is_basis,
@ -128,11 +130,69 @@ def instantiate_name(original_name, instantiations):
for inst in instantiations:
# Ensure the first character of the type is capitalized
name = inst.instantiated_name()
# Using `capitalize` on the complete causes other caps to be lower case
# 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))
class InstantiatedGlobalFunction(parser.GlobalFunction):
"""
Instantiate global functions.
E.g.
template<T = {double}>
T add(const T& x, const T& y);
"""
def __init__(self, original, instantiations=(), new_name=''):
self.original = original
self.instantiations = instantiations
self.template = ''
self.parent = original.parent
if not original.template:
self.name = original.name
self.return_type = original.return_type
self.args = original.args
else:
self.name = instantiate_name(
original.name, instantiations) if not new_name else new_name
self.return_type = instantiate_return_type(
original.return_type,
self.original.template.typenames,
self.instantiations,
# Keyword type name `This` should already be replaced in the
# previous class template instantiation round.
cpp_typename='',
)
instantiated_args = instantiate_args_list(
original.args.args_list,
self.original.template.typenames,
self.instantiations,
# Keyword type name `This` should already be replaced in the
# previous class template instantiation round.
cpp_typename='',
)
self.args = parser.ArgumentList(instantiated_args)
super().__init__(self.name,
self.return_type,
self.args,
self.template,
parent=self.parent)
def to_cpp(self):
"""Generate the C++ code for wrapping."""
if self.original.template:
instantiated_names = [inst.instantiated_name() for inst in self.instantiations]
ret = "{}<{}>".format(self.original.name, ",".join(instantiated_names))
else:
ret = self.original.name
return ret
def __repr__(self):
return "Instantiated {}".format(
super(InstantiatedGlobalFunction, self).__repr__()
)
class InstantiatedMethod(parser.Method):
"""
@ -396,17 +456,38 @@ def instantiate_namespace_inplace(namespace):
InstantiatedClass(original_class,
list(instantiations)))
elif isinstance(element, parser.GlobalFunction):
original_func = element
if not original_func.template:
instantiated_content.append(
InstantiatedGlobalFunction(original_func, []))
else:
# Use itertools to get all possible combinations of instantiations
# Works even if one template does not have an instantiation list
for instantiations in itertools.product(
*original_func.template.instantiations):
instantiated_content.append(
InstantiatedGlobalFunction(original_func,
list(instantiations)))
elif isinstance(element, parser.TypedefTemplateInstantiation):
typedef_inst = element
original_class = namespace.top_level().find_class(
top_level = namespace.top_level()
original_element = top_level.find_class_or_function(
typedef_inst.typename)
# Check if element is a typedef'd class or function.
if isinstance(original_element, parser.Class):
typedef_content.append(
InstantiatedClass(
original_class,
InstantiatedClass(original_element,
typedef_inst.typename.instantiations,
typedef_inst.new_name
)
)
typedef_inst.new_name))
elif isinstance(original_element, parser.GlobalFunction):
typedef_content.append(
InstantiatedGlobalFunction(
original_element, typedef_inst.typename.instantiations,
typedef_inst.new_name))
elif isinstance(element, parser.Namespace):
instantiate_namespace_inplace(element)
instantiated_content.append(element)

View File

@ -1 +1,3 @@
pyparsing
pytest
loguru

View File

@ -7,6 +7,12 @@
%
%-------Methods-------
%argChar(char a) : returns void
%argChar(char a) : returns void
%argChar(char a) : returns void
%argChar(char a) : returns void
%argChar(char a) : returns void
%argChar(char a) : returns void
%argChar(char a) : returns void
%argUChar(unsigned char a) : returns void
%dim() : returns int
%eigenArguments(Vector v, Matrix m) : returns void
@ -49,6 +55,42 @@ classdef Point2 < handle
geometry_wrapper(4, this, varargin{:});
return
end
% ARGCHAR usage: argChar(char a) : returns void
% Doxygen can be found at https://gtsam.org/doxygen/
if length(varargin) == 1 && isa(varargin{1},'char')
geometry_wrapper(5, this, varargin{:});
return
end
% ARGCHAR usage: argChar(char a) : returns void
% Doxygen can be found at https://gtsam.org/doxygen/
if length(varargin) == 1 && isa(varargin{1},'char')
geometry_wrapper(6, this, varargin{:});
return
end
% ARGCHAR usage: argChar(char a) : returns void
% Doxygen can be found at https://gtsam.org/doxygen/
if length(varargin) == 1 && isa(varargin{1},'char')
geometry_wrapper(7, this, varargin{:});
return
end
% ARGCHAR usage: argChar(char a) : returns void
% Doxygen can be found at https://gtsam.org/doxygen/
if length(varargin) == 1 && isa(varargin{1},'char')
geometry_wrapper(8, this, varargin{:});
return
end
% ARGCHAR usage: argChar(char a) : returns void
% Doxygen can be found at https://gtsam.org/doxygen/
if length(varargin) == 1 && isa(varargin{1},'char')
geometry_wrapper(9, this, varargin{:});
return
end
% ARGCHAR usage: argChar(char a) : returns void
% Doxygen can be found at https://gtsam.org/doxygen/
if length(varargin) == 1 && isa(varargin{1},'char')
geometry_wrapper(10, this, varargin{:});
return
end
error('Arguments do not match any overload of function gtsam.Point2.argChar');
end
@ -56,7 +98,7 @@ classdef Point2 < handle
% ARGUCHAR usage: argUChar(unsigned char a) : returns void
% Doxygen can be found at https://gtsam.org/doxygen/
if length(varargin) == 1 && isa(varargin{1},'unsigned char')
geometry_wrapper(5, this, varargin{:});
geometry_wrapper(11, this, varargin{:});
return
end
error('Arguments do not match any overload of function gtsam.Point2.argUChar');
@ -66,7 +108,7 @@ classdef Point2 < handle
% DIM usage: dim() : returns int
% Doxygen can be found at https://gtsam.org/doxygen/
if length(varargin) == 0
varargout{1} = geometry_wrapper(6, this, varargin{:});
varargout{1} = geometry_wrapper(12, this, varargin{:});
return
end
error('Arguments do not match any overload of function gtsam.Point2.dim');
@ -76,7 +118,7 @@ classdef Point2 < handle
% EIGENARGUMENTS usage: eigenArguments(Vector v, Matrix m) : returns void
% Doxygen can be found at https://gtsam.org/doxygen/
if length(varargin) == 2 && isa(varargin{1},'double') && size(varargin{1},2)==1 && isa(varargin{2},'double')
geometry_wrapper(7, this, varargin{:});
geometry_wrapper(13, this, varargin{:});
return
end
error('Arguments do not match any overload of function gtsam.Point2.eigenArguments');
@ -86,7 +128,7 @@ classdef Point2 < handle
% RETURNCHAR usage: returnChar() : returns char
% Doxygen can be found at https://gtsam.org/doxygen/
if length(varargin) == 0
varargout{1} = geometry_wrapper(8, this, varargin{:});
varargout{1} = geometry_wrapper(14, this, varargin{:});
return
end
error('Arguments do not match any overload of function gtsam.Point2.returnChar');
@ -96,7 +138,7 @@ classdef Point2 < handle
% VECTORCONFUSION usage: vectorConfusion() : returns VectorNotEigen
% Doxygen can be found at https://gtsam.org/doxygen/
if length(varargin) == 0
varargout{1} = geometry_wrapper(9, this, varargin{:});
varargout{1} = geometry_wrapper(15, this, varargin{:});
return
end
error('Arguments do not match any overload of function gtsam.Point2.vectorConfusion');
@ -106,7 +148,7 @@ classdef Point2 < handle
% X usage: x() : returns double
% Doxygen can be found at https://gtsam.org/doxygen/
if length(varargin) == 0
varargout{1} = geometry_wrapper(10, this, varargin{:});
varargout{1} = geometry_wrapper(16, this, varargin{:});
return
end
error('Arguments do not match any overload of function gtsam.Point2.x');
@ -116,7 +158,7 @@ classdef Point2 < handle
% Y usage: y() : returns double
% Doxygen can be found at https://gtsam.org/doxygen/
if length(varargin) == 0
varargout{1} = geometry_wrapper(11, this, varargin{:});
varargout{1} = geometry_wrapper(17, this, varargin{:});
return
end
error('Arguments do not match any overload of function gtsam.Point2.y');

View File

@ -23,9 +23,9 @@ classdef Point3 < handle
function obj = Point3(varargin)
if nargin == 2 && isa(varargin{1}, 'uint64') && varargin{1} == uint64(5139824614673773682)
my_ptr = varargin{2};
geometry_wrapper(12, my_ptr);
geometry_wrapper(18, my_ptr);
elseif nargin == 3 && isa(varargin{1},'double') && isa(varargin{2},'double') && isa(varargin{3},'double')
my_ptr = geometry_wrapper(13, varargin{1}, varargin{2}, varargin{3});
my_ptr = geometry_wrapper(19, varargin{1}, varargin{2}, varargin{3});
else
error('Arguments do not match any overload of gtsam.Point3 constructor');
end
@ -33,7 +33,7 @@ classdef Point3 < handle
end
function delete(obj)
geometry_wrapper(14, obj.ptr_gtsamPoint3);
geometry_wrapper(20, obj.ptr_gtsamPoint3);
end
function display(obj), obj.print(''); end
@ -44,7 +44,7 @@ classdef Point3 < handle
% NORM usage: norm() : returns double
% Doxygen can be found at https://gtsam.org/doxygen/
if length(varargin) == 0
varargout{1} = geometry_wrapper(15, this, varargin{:});
varargout{1} = geometry_wrapper(21, this, varargin{:});
return
end
error('Arguments do not match any overload of function gtsam.Point3.norm');
@ -54,7 +54,7 @@ classdef Point3 < handle
% STRING_SERIALIZE usage: string_serialize() : returns string
% Doxygen can be found at https://gtsam.org/doxygen/
if length(varargin) == 0
varargout{1} = geometry_wrapper(16, this, varargin{:});
varargout{1} = geometry_wrapper(22, this, varargin{:});
else
error('Arguments do not match any overload of function gtsam.Point3.string_serialize');
end
@ -71,7 +71,7 @@ classdef Point3 < handle
% STATICFUNCTIONRET usage: StaticFunctionRet(double z) : returns Point3
% Doxygen can be found at https://gtsam.org/doxygen/
if length(varargin) == 1 && isa(varargin{1},'double')
varargout{1} = geometry_wrapper(17, varargin{:});
varargout{1} = geometry_wrapper(23, varargin{:});
return
end
@ -82,7 +82,7 @@ classdef Point3 < handle
% STATICFUNCTION usage: staticFunction() : returns double
% Doxygen can be found at https://gtsam.org/doxygen/
if length(varargin) == 0
varargout{1} = geometry_wrapper(18, varargin{:});
varargout{1} = geometry_wrapper(24, varargin{:});
return
end
@ -93,7 +93,7 @@ classdef Point3 < handle
% STRING_DESERIALIZE usage: string_deserialize() : returns gtsam.Point3
% Doxygen can be found at https://gtsam.org/doxygen/
if length(varargin) == 1
varargout{1} = geometry_wrapper(19, varargin{:});
varargout{1} = geometry_wrapper(25, varargin{:});
else
error('Arguments do not match any overload of function gtsam.Point3.string_deserialize');
end

View File

@ -11,9 +11,9 @@ classdef MyBase < handle
if nargin == 2
my_ptr = varargin{2};
else
my_ptr = geometry_wrapper(45, varargin{2});
my_ptr = geometry_wrapper(51, varargin{2});
end
geometry_wrapper(44, my_ptr);
geometry_wrapper(50, my_ptr);
else
error('Arguments do not match any overload of MyBase constructor');
end
@ -21,7 +21,7 @@ classdef MyBase < handle
end
function delete(obj)
geometry_wrapper(46, obj.ptr_MyBase);
geometry_wrapper(52, obj.ptr_MyBase);
end
function display(obj), obj.print(''); end

View File

@ -12,9 +12,9 @@ classdef MyFactorPosePoint2 < handle
function obj = MyFactorPosePoint2(varargin)
if nargin == 2 && isa(varargin{1}, 'uint64') && varargin{1} == uint64(5139824614673773682)
my_ptr = varargin{2};
geometry_wrapper(93, my_ptr);
geometry_wrapper(99, my_ptr);
elseif nargin == 4 && isa(varargin{1},'numeric') && isa(varargin{2},'numeric') && isa(varargin{3},'double') && isa(varargin{4},'gtsam.noiseModel.Base')
my_ptr = geometry_wrapper(94, varargin{1}, varargin{2}, varargin{3}, varargin{4});
my_ptr = geometry_wrapper(100, varargin{1}, varargin{2}, varargin{3}, varargin{4});
else
error('Arguments do not match any overload of MyFactorPosePoint2 constructor');
end
@ -22,7 +22,7 @@ classdef MyFactorPosePoint2 < handle
end
function delete(obj)
geometry_wrapper(95, obj.ptr_MyFactorPosePoint2);
geometry_wrapper(101, obj.ptr_MyFactorPosePoint2);
end
function display(obj), obj.print(''); end

View File

@ -34,11 +34,11 @@ classdef MyTemplateMatrix < MyBase
if nargin == 2
my_ptr = varargin{2};
else
my_ptr = geometry_wrapper(64, varargin{2});
my_ptr = geometry_wrapper(70, varargin{2});
end
base_ptr = geometry_wrapper(63, my_ptr);
base_ptr = geometry_wrapper(69, my_ptr);
elseif nargin == 0
[ my_ptr, base_ptr ] = geometry_wrapper(65);
[ my_ptr, base_ptr ] = geometry_wrapper(71);
else
error('Arguments do not match any overload of MyTemplateMatrix constructor');
end
@ -47,7 +47,7 @@ classdef MyTemplateMatrix < MyBase
end
function delete(obj)
geometry_wrapper(66, obj.ptr_MyTemplateMatrix);
geometry_wrapper(72, obj.ptr_MyTemplateMatrix);
end
function display(obj), obj.print(''); end
@ -58,7 +58,7 @@ classdef MyTemplateMatrix < MyBase
% ACCEPT_T usage: accept_T(Matrix value) : returns void
% Doxygen can be found at https://gtsam.org/doxygen/
if length(varargin) == 1 && isa(varargin{1},'double')
geometry_wrapper(67, this, varargin{:});
geometry_wrapper(73, this, varargin{:});
return
end
error('Arguments do not match any overload of function MyTemplateMatrix.accept_T');
@ -68,7 +68,7 @@ classdef MyTemplateMatrix < MyBase
% ACCEPT_TPTR usage: accept_Tptr(Matrix value) : returns void
% Doxygen can be found at https://gtsam.org/doxygen/
if length(varargin) == 1 && isa(varargin{1},'double')
geometry_wrapper(68, this, varargin{:});
geometry_wrapper(74, this, varargin{:});
return
end
error('Arguments do not match any overload of function MyTemplateMatrix.accept_Tptr');
@ -78,7 +78,7 @@ classdef MyTemplateMatrix < MyBase
% CREATE_MIXEDPTRS usage: create_MixedPtrs() : returns pair< Matrix, Matrix >
% Doxygen can be found at https://gtsam.org/doxygen/
if length(varargin) == 0
[ varargout{1} varargout{2} ] = geometry_wrapper(69, this, varargin{:});
[ varargout{1} varargout{2} ] = geometry_wrapper(75, this, varargin{:});
return
end
error('Arguments do not match any overload of function MyTemplateMatrix.create_MixedPtrs');
@ -88,7 +88,7 @@ classdef MyTemplateMatrix < MyBase
% CREATE_PTRS usage: create_ptrs() : returns pair< Matrix, Matrix >
% Doxygen can be found at https://gtsam.org/doxygen/
if length(varargin) == 0
[ varargout{1} varargout{2} ] = geometry_wrapper(70, this, varargin{:});
[ varargout{1} varargout{2} ] = geometry_wrapper(76, this, varargin{:});
return
end
error('Arguments do not match any overload of function MyTemplateMatrix.create_ptrs');
@ -98,7 +98,7 @@ classdef MyTemplateMatrix < MyBase
% RETURN_T usage: return_T(Matrix value) : returns Matrix
% Doxygen can be found at https://gtsam.org/doxygen/
if length(varargin) == 1 && isa(varargin{1},'double')
varargout{1} = geometry_wrapper(71, this, varargin{:});
varargout{1} = geometry_wrapper(77, this, varargin{:});
return
end
error('Arguments do not match any overload of function MyTemplateMatrix.return_T');
@ -108,7 +108,7 @@ classdef MyTemplateMatrix < MyBase
% RETURN_TPTR usage: return_Tptr(Matrix value) : returns Matrix
% Doxygen can be found at https://gtsam.org/doxygen/
if length(varargin) == 1 && isa(varargin{1},'double')
varargout{1} = geometry_wrapper(72, this, varargin{:});
varargout{1} = geometry_wrapper(78, this, varargin{:});
return
end
error('Arguments do not match any overload of function MyTemplateMatrix.return_Tptr');
@ -118,7 +118,7 @@ classdef MyTemplateMatrix < MyBase
% RETURN_PTRS usage: return_ptrs(Matrix p1, Matrix p2) : returns pair< Matrix, Matrix >
% Doxygen can be found at https://gtsam.org/doxygen/
if length(varargin) == 2 && isa(varargin{1},'double') && isa(varargin{2},'double')
[ varargout{1} varargout{2} ] = geometry_wrapper(73, this, varargin{:});
[ varargout{1} varargout{2} ] = geometry_wrapper(79, this, varargin{:});
return
end
error('Arguments do not match any overload of function MyTemplateMatrix.return_ptrs');
@ -128,7 +128,7 @@ classdef MyTemplateMatrix < MyBase
% TEMPLATEDMETHODMATRIX usage: templatedMethodMatrix(Matrix t) : returns Matrix
% Doxygen can be found at https://gtsam.org/doxygen/
if length(varargin) == 1 && isa(varargin{1},'double')
varargout{1} = geometry_wrapper(74, this, varargin{:});
varargout{1} = geometry_wrapper(80, this, varargin{:});
return
end
error('Arguments do not match any overload of function MyTemplateMatrix.templatedMethodMatrix');
@ -138,7 +138,7 @@ classdef MyTemplateMatrix < MyBase
% TEMPLATEDMETHODPOINT2 usage: templatedMethodPoint2(Point2 t) : returns Point2
% Doxygen can be found at https://gtsam.org/doxygen/
if length(varargin) == 1 && isa(varargin{1},'double') && size(varargin{1},1)==2 && size(varargin{1},2)==1
varargout{1} = geometry_wrapper(75, this, varargin{:});
varargout{1} = geometry_wrapper(81, this, varargin{:});
return
end
error('Arguments do not match any overload of function MyTemplateMatrix.templatedMethodPoint2');
@ -148,7 +148,7 @@ classdef MyTemplateMatrix < MyBase
% TEMPLATEDMETHODPOINT3 usage: templatedMethodPoint3(Point3 t) : returns Point3
% Doxygen can be found at https://gtsam.org/doxygen/
if length(varargin) == 1 && isa(varargin{1},'double') && size(varargin{1},1)==3 && size(varargin{1},2)==1
varargout{1} = geometry_wrapper(76, this, varargin{:});
varargout{1} = geometry_wrapper(82, this, varargin{:});
return
end
error('Arguments do not match any overload of function MyTemplateMatrix.templatedMethodPoint3');
@ -158,7 +158,7 @@ classdef MyTemplateMatrix < MyBase
% TEMPLATEDMETHODVECTOR usage: templatedMethodVector(Vector t) : returns Vector
% Doxygen can be found at https://gtsam.org/doxygen/
if length(varargin) == 1 && isa(varargin{1},'double') && size(varargin{1},2)==1
varargout{1} = geometry_wrapper(77, this, varargin{:});
varargout{1} = geometry_wrapper(83, this, varargin{:});
return
end
error('Arguments do not match any overload of function MyTemplateMatrix.templatedMethodVector');
@ -171,7 +171,7 @@ classdef MyTemplateMatrix < MyBase
% LEVEL usage: Level(Matrix K) : returns MyTemplateMatrix
% Doxygen can be found at https://gtsam.org/doxygen/
if length(varargin) == 1 && isa(varargin{1},'double')
varargout{1} = geometry_wrapper(78, varargin{:});
varargout{1} = geometry_wrapper(84, varargin{:});
return
end

View File

@ -34,11 +34,11 @@ classdef MyTemplatePoint2 < MyBase
if nargin == 2
my_ptr = varargin{2};
else
my_ptr = geometry_wrapper(48, varargin{2});
my_ptr = geometry_wrapper(54, varargin{2});
end
base_ptr = geometry_wrapper(47, my_ptr);
base_ptr = geometry_wrapper(53, my_ptr);
elseif nargin == 0
[ my_ptr, base_ptr ] = geometry_wrapper(49);
[ my_ptr, base_ptr ] = geometry_wrapper(55);
else
error('Arguments do not match any overload of MyTemplatePoint2 constructor');
end
@ -47,7 +47,7 @@ classdef MyTemplatePoint2 < MyBase
end
function delete(obj)
geometry_wrapper(50, obj.ptr_MyTemplatePoint2);
geometry_wrapper(56, obj.ptr_MyTemplatePoint2);
end
function display(obj), obj.print(''); end
@ -58,7 +58,7 @@ classdef MyTemplatePoint2 < MyBase
% ACCEPT_T usage: accept_T(Point2 value) : returns void
% Doxygen can be found at https://gtsam.org/doxygen/
if length(varargin) == 1 && isa(varargin{1},'double') && size(varargin{1},1)==2 && size(varargin{1},2)==1
geometry_wrapper(51, this, varargin{:});
geometry_wrapper(57, this, varargin{:});
return
end
error('Arguments do not match any overload of function MyTemplatePoint2.accept_T');
@ -68,7 +68,7 @@ classdef MyTemplatePoint2 < MyBase
% ACCEPT_TPTR usage: accept_Tptr(Point2 value) : returns void
% Doxygen can be found at https://gtsam.org/doxygen/
if length(varargin) == 1 && isa(varargin{1},'double') && size(varargin{1},1)==2 && size(varargin{1},2)==1
geometry_wrapper(52, this, varargin{:});
geometry_wrapper(58, this, varargin{:});
return
end
error('Arguments do not match any overload of function MyTemplatePoint2.accept_Tptr');
@ -78,7 +78,7 @@ classdef MyTemplatePoint2 < MyBase
% CREATE_MIXEDPTRS usage: create_MixedPtrs() : returns pair< Point2, Point2 >
% Doxygen can be found at https://gtsam.org/doxygen/
if length(varargin) == 0
[ varargout{1} varargout{2} ] = geometry_wrapper(53, this, varargin{:});
[ varargout{1} varargout{2} ] = geometry_wrapper(59, this, varargin{:});
return
end
error('Arguments do not match any overload of function MyTemplatePoint2.create_MixedPtrs');
@ -88,7 +88,7 @@ classdef MyTemplatePoint2 < MyBase
% CREATE_PTRS usage: create_ptrs() : returns pair< Point2, Point2 >
% Doxygen can be found at https://gtsam.org/doxygen/
if length(varargin) == 0
[ varargout{1} varargout{2} ] = geometry_wrapper(54, this, varargin{:});
[ varargout{1} varargout{2} ] = geometry_wrapper(60, this, varargin{:});
return
end
error('Arguments do not match any overload of function MyTemplatePoint2.create_ptrs');
@ -98,7 +98,7 @@ classdef MyTemplatePoint2 < MyBase
% RETURN_T usage: return_T(Point2 value) : returns Point2
% Doxygen can be found at https://gtsam.org/doxygen/
if length(varargin) == 1 && isa(varargin{1},'double') && size(varargin{1},1)==2 && size(varargin{1},2)==1
varargout{1} = geometry_wrapper(55, this, varargin{:});
varargout{1} = geometry_wrapper(61, this, varargin{:});
return
end
error('Arguments do not match any overload of function MyTemplatePoint2.return_T');
@ -108,7 +108,7 @@ classdef MyTemplatePoint2 < MyBase
% RETURN_TPTR usage: return_Tptr(Point2 value) : returns Point2
% Doxygen can be found at https://gtsam.org/doxygen/
if length(varargin) == 1 && isa(varargin{1},'double') && size(varargin{1},1)==2 && size(varargin{1},2)==1
varargout{1} = geometry_wrapper(56, this, varargin{:});
varargout{1} = geometry_wrapper(62, this, varargin{:});
return
end
error('Arguments do not match any overload of function MyTemplatePoint2.return_Tptr');
@ -118,7 +118,7 @@ classdef MyTemplatePoint2 < MyBase
% RETURN_PTRS usage: return_ptrs(Point2 p1, Point2 p2) : returns pair< Point2, Point2 >
% Doxygen can be found at https://gtsam.org/doxygen/
if length(varargin) == 2 && isa(varargin{1},'double') && size(varargin{1},1)==2 && size(varargin{1},2)==1 && isa(varargin{2},'double') && size(varargin{2},1)==2 && size(varargin{2},2)==1
[ varargout{1} varargout{2} ] = geometry_wrapper(57, this, varargin{:});
[ varargout{1} varargout{2} ] = geometry_wrapper(63, this, varargin{:});
return
end
error('Arguments do not match any overload of function MyTemplatePoint2.return_ptrs');
@ -128,7 +128,7 @@ classdef MyTemplatePoint2 < MyBase
% TEMPLATEDMETHODMATRIX usage: templatedMethodMatrix(Matrix t) : returns Matrix
% Doxygen can be found at https://gtsam.org/doxygen/
if length(varargin) == 1 && isa(varargin{1},'double')
varargout{1} = geometry_wrapper(58, this, varargin{:});
varargout{1} = geometry_wrapper(64, this, varargin{:});
return
end
error('Arguments do not match any overload of function MyTemplatePoint2.templatedMethodMatrix');
@ -138,7 +138,7 @@ classdef MyTemplatePoint2 < MyBase
% TEMPLATEDMETHODPOINT2 usage: templatedMethodPoint2(Point2 t) : returns Point2
% Doxygen can be found at https://gtsam.org/doxygen/
if length(varargin) == 1 && isa(varargin{1},'double') && size(varargin{1},1)==2 && size(varargin{1},2)==1
varargout{1} = geometry_wrapper(59, this, varargin{:});
varargout{1} = geometry_wrapper(65, this, varargin{:});
return
end
error('Arguments do not match any overload of function MyTemplatePoint2.templatedMethodPoint2');
@ -148,7 +148,7 @@ classdef MyTemplatePoint2 < MyBase
% TEMPLATEDMETHODPOINT3 usage: templatedMethodPoint3(Point3 t) : returns Point3
% Doxygen can be found at https://gtsam.org/doxygen/
if length(varargin) == 1 && isa(varargin{1},'double') && size(varargin{1},1)==3 && size(varargin{1},2)==1
varargout{1} = geometry_wrapper(60, this, varargin{:});
varargout{1} = geometry_wrapper(66, this, varargin{:});
return
end
error('Arguments do not match any overload of function MyTemplatePoint2.templatedMethodPoint3');
@ -158,7 +158,7 @@ classdef MyTemplatePoint2 < MyBase
% TEMPLATEDMETHODVECTOR usage: templatedMethodVector(Vector t) : returns Vector
% Doxygen can be found at https://gtsam.org/doxygen/
if length(varargin) == 1 && isa(varargin{1},'double') && size(varargin{1},2)==1
varargout{1} = geometry_wrapper(61, this, varargin{:});
varargout{1} = geometry_wrapper(67, this, varargin{:});
return
end
error('Arguments do not match any overload of function MyTemplatePoint2.templatedMethodVector');
@ -171,7 +171,7 @@ classdef MyTemplatePoint2 < MyBase
% LEVEL usage: Level(Point2 K) : returns MyTemplatePoint2
% Doxygen can be found at https://gtsam.org/doxygen/
if length(varargin) == 1 && isa(varargin{1},'double') && size(varargin{1},1)==2 && size(varargin{1},2)==1
varargout{1} = geometry_wrapper(62, varargin{:});
varargout{1} = geometry_wrapper(68, varargin{:});
return
end

View File

@ -12,9 +12,9 @@ classdef MyVector12 < handle
function obj = MyVector12(varargin)
if nargin == 2 && isa(varargin{1}, 'uint64') && varargin{1} == uint64(5139824614673773682)
my_ptr = varargin{2};
geometry_wrapper(86, my_ptr);
geometry_wrapper(92, my_ptr);
elseif nargin == 0
my_ptr = geometry_wrapper(87);
my_ptr = geometry_wrapper(93);
else
error('Arguments do not match any overload of MyVector12 constructor');
end
@ -22,7 +22,7 @@ classdef MyVector12 < handle
end
function delete(obj)
geometry_wrapper(88, obj.ptr_MyVector12);
geometry_wrapper(94, obj.ptr_MyVector12);
end
function display(obj), obj.print(''); end

View File

@ -12,9 +12,9 @@ classdef MyVector3 < handle
function obj = MyVector3(varargin)
if nargin == 2 && isa(varargin{1}, 'uint64') && varargin{1} == uint64(5139824614673773682)
my_ptr = varargin{2};
geometry_wrapper(83, my_ptr);
geometry_wrapper(89, my_ptr);
elseif nargin == 0
my_ptr = geometry_wrapper(84);
my_ptr = geometry_wrapper(90);
else
error('Arguments do not match any overload of MyVector3 constructor');
end
@ -22,7 +22,7 @@ classdef MyVector3 < handle
end
function delete(obj)
geometry_wrapper(85, obj.ptr_MyVector3);
geometry_wrapper(91, obj.ptr_MyVector3);
end
function display(obj), obj.print(''); end

View File

@ -35,11 +35,11 @@ classdef Test < handle
function obj = Test(varargin)
if nargin == 2 && isa(varargin{1}, 'uint64') && varargin{1} == uint64(5139824614673773682)
my_ptr = varargin{2};
geometry_wrapper(20, my_ptr);
geometry_wrapper(26, my_ptr);
elseif nargin == 0
my_ptr = geometry_wrapper(21);
my_ptr = geometry_wrapper(27);
elseif nargin == 2 && isa(varargin{1},'double') && isa(varargin{2},'double')
my_ptr = geometry_wrapper(22, varargin{1}, varargin{2});
my_ptr = geometry_wrapper(28, varargin{1}, varargin{2});
else
error('Arguments do not match any overload of Test constructor');
end
@ -47,7 +47,7 @@ classdef Test < handle
end
function delete(obj)
geometry_wrapper(23, obj.ptr_Test);
geometry_wrapper(29, obj.ptr_Test);
end
function display(obj), obj.print(''); end
@ -58,7 +58,7 @@ classdef Test < handle
% ARG_EIGENCONSTREF usage: arg_EigenConstRef(Matrix value) : returns void
% Doxygen can be found at https://gtsam.org/doxygen/
if length(varargin) == 1 && isa(varargin{1},'double')
geometry_wrapper(24, this, varargin{:});
geometry_wrapper(30, this, varargin{:});
return
end
error('Arguments do not match any overload of function Test.arg_EigenConstRef');
@ -68,7 +68,7 @@ classdef Test < handle
% CREATE_MIXEDPTRS usage: create_MixedPtrs() : returns pair< Test, Test >
% Doxygen can be found at https://gtsam.org/doxygen/
if length(varargin) == 0
[ varargout{1} varargout{2} ] = geometry_wrapper(25, this, varargin{:});
[ varargout{1} varargout{2} ] = geometry_wrapper(31, this, varargin{:});
return
end
error('Arguments do not match any overload of function Test.create_MixedPtrs');
@ -78,7 +78,7 @@ classdef Test < handle
% CREATE_PTRS usage: create_ptrs() : returns pair< Test, Test >
% Doxygen can be found at https://gtsam.org/doxygen/
if length(varargin) == 0
[ varargout{1} varargout{2} ] = geometry_wrapper(26, this, varargin{:});
[ varargout{1} varargout{2} ] = geometry_wrapper(32, this, varargin{:});
return
end
error('Arguments do not match any overload of function Test.create_ptrs');
@ -88,7 +88,7 @@ classdef Test < handle
% PRINT usage: print() : returns void
% Doxygen can be found at https://gtsam.org/doxygen/
if length(varargin) == 0
geometry_wrapper(27, this, varargin{:});
geometry_wrapper(33, this, varargin{:});
return
end
error('Arguments do not match any overload of function Test.print');
@ -98,7 +98,7 @@ classdef Test < handle
% RETURN_POINT2PTR usage: return_Point2Ptr(bool value) : returns Point2
% Doxygen can be found at https://gtsam.org/doxygen/
if length(varargin) == 1 && isa(varargin{1},'logical')
varargout{1} = geometry_wrapper(28, this, varargin{:});
varargout{1} = geometry_wrapper(34, this, varargin{:});
return
end
error('Arguments do not match any overload of function Test.return_Point2Ptr');
@ -108,7 +108,7 @@ classdef Test < handle
% RETURN_TEST usage: return_Test(Test value) : returns Test
% Doxygen can be found at https://gtsam.org/doxygen/
if length(varargin) == 1 && isa(varargin{1},'Test')
varargout{1} = geometry_wrapper(29, this, varargin{:});
varargout{1} = geometry_wrapper(35, this, varargin{:});
return
end
error('Arguments do not match any overload of function Test.return_Test');
@ -118,7 +118,7 @@ classdef Test < handle
% RETURN_TESTPTR usage: return_TestPtr(Test value) : returns Test
% Doxygen can be found at https://gtsam.org/doxygen/
if length(varargin) == 1 && isa(varargin{1},'Test')
varargout{1} = geometry_wrapper(30, this, varargin{:});
varargout{1} = geometry_wrapper(36, this, varargin{:});
return
end
error('Arguments do not match any overload of function Test.return_TestPtr');
@ -128,7 +128,7 @@ classdef Test < handle
% RETURN_BOOL usage: return_bool(bool value) : returns bool
% Doxygen can be found at https://gtsam.org/doxygen/
if length(varargin) == 1 && isa(varargin{1},'logical')
varargout{1} = geometry_wrapper(31, this, varargin{:});
varargout{1} = geometry_wrapper(37, this, varargin{:});
return
end
error('Arguments do not match any overload of function Test.return_bool');
@ -138,7 +138,7 @@ classdef Test < handle
% RETURN_DOUBLE usage: return_double(double value) : returns double
% Doxygen can be found at https://gtsam.org/doxygen/
if length(varargin) == 1 && isa(varargin{1},'double')
varargout{1} = geometry_wrapper(32, this, varargin{:});
varargout{1} = geometry_wrapper(38, this, varargin{:});
return
end
error('Arguments do not match any overload of function Test.return_double');
@ -148,7 +148,7 @@ classdef Test < handle
% RETURN_FIELD usage: return_field(Test t) : returns bool
% Doxygen can be found at https://gtsam.org/doxygen/
if length(varargin) == 1 && isa(varargin{1},'Test')
varargout{1} = geometry_wrapper(33, this, varargin{:});
varargout{1} = geometry_wrapper(39, this, varargin{:});
return
end
error('Arguments do not match any overload of function Test.return_field');
@ -158,7 +158,7 @@ classdef Test < handle
% RETURN_INT usage: return_int(int value) : returns int
% Doxygen can be found at https://gtsam.org/doxygen/
if length(varargin) == 1 && isa(varargin{1},'numeric')
varargout{1} = geometry_wrapper(34, this, varargin{:});
varargout{1} = geometry_wrapper(40, this, varargin{:});
return
end
error('Arguments do not match any overload of function Test.return_int');
@ -168,7 +168,7 @@ classdef Test < handle
% RETURN_MATRIX1 usage: return_matrix1(Matrix value) : returns Matrix
% Doxygen can be found at https://gtsam.org/doxygen/
if length(varargin) == 1 && isa(varargin{1},'double')
varargout{1} = geometry_wrapper(35, this, varargin{:});
varargout{1} = geometry_wrapper(41, this, varargin{:});
return
end
error('Arguments do not match any overload of function Test.return_matrix1');
@ -178,7 +178,7 @@ classdef Test < handle
% RETURN_MATRIX2 usage: return_matrix2(Matrix value) : returns Matrix
% Doxygen can be found at https://gtsam.org/doxygen/
if length(varargin) == 1 && isa(varargin{1},'double')
varargout{1} = geometry_wrapper(36, this, varargin{:});
varargout{1} = geometry_wrapper(42, this, varargin{:});
return
end
error('Arguments do not match any overload of function Test.return_matrix2');
@ -188,13 +188,13 @@ classdef Test < handle
% RETURN_PAIR usage: return_pair(Vector v, Matrix A) : returns pair< Vector, Matrix >
% Doxygen can be found at https://gtsam.org/doxygen/
if length(varargin) == 2 && isa(varargin{1},'double') && size(varargin{1},2)==1 && isa(varargin{2},'double')
[ varargout{1} varargout{2} ] = geometry_wrapper(37, this, varargin{:});
[ varargout{1} varargout{2} ] = geometry_wrapper(43, this, varargin{:});
return
end
% RETURN_PAIR usage: return_pair(Vector v) : returns pair< Vector, Matrix >
% Doxygen can be found at https://gtsam.org/doxygen/
if length(varargin) == 1 && isa(varargin{1},'double') && size(varargin{1},2)==1
[ varargout{1} varargout{2} ] = geometry_wrapper(38, this, varargin{:});
[ varargout{1} varargout{2} ] = geometry_wrapper(44, this, varargin{:});
return
end
error('Arguments do not match any overload of function Test.return_pair');
@ -204,7 +204,7 @@ classdef Test < handle
% RETURN_PTRS usage: return_ptrs(Test p1, Test p2) : returns pair< Test, Test >
% Doxygen can be found at https://gtsam.org/doxygen/
if length(varargin) == 2 && isa(varargin{1},'Test') && isa(varargin{2},'Test')
[ varargout{1} varargout{2} ] = geometry_wrapper(39, this, varargin{:});
[ varargout{1} varargout{2} ] = geometry_wrapper(45, this, varargin{:});
return
end
error('Arguments do not match any overload of function Test.return_ptrs');
@ -214,7 +214,7 @@ classdef Test < handle
% RETURN_SIZE_T usage: return_size_t(size_t value) : returns size_t
% Doxygen can be found at https://gtsam.org/doxygen/
if length(varargin) == 1 && isa(varargin{1},'numeric')
varargout{1} = geometry_wrapper(40, this, varargin{:});
varargout{1} = geometry_wrapper(46, this, varargin{:});
return
end
error('Arguments do not match any overload of function Test.return_size_t');
@ -224,7 +224,7 @@ classdef Test < handle
% RETURN_STRING usage: return_string(string value) : returns string
% Doxygen can be found at https://gtsam.org/doxygen/
if length(varargin) == 1 && isa(varargin{1},'char')
varargout{1} = geometry_wrapper(41, this, varargin{:});
varargout{1} = geometry_wrapper(47, this, varargin{:});
return
end
error('Arguments do not match any overload of function Test.return_string');
@ -234,7 +234,7 @@ classdef Test < handle
% RETURN_VECTOR1 usage: return_vector1(Vector value) : returns Vector
% Doxygen can be found at https://gtsam.org/doxygen/
if length(varargin) == 1 && isa(varargin{1},'double') && size(varargin{1},2)==1
varargout{1} = geometry_wrapper(42, this, varargin{:});
varargout{1} = geometry_wrapper(48, this, varargin{:});
return
end
error('Arguments do not match any overload of function Test.return_vector1');
@ -244,7 +244,7 @@ classdef Test < handle
% RETURN_VECTOR2 usage: return_vector2(Vector value) : returns Vector
% Doxygen can be found at https://gtsam.org/doxygen/
if length(varargin) == 1 && isa(varargin{1},'double') && size(varargin{1},2)==1
varargout{1} = geometry_wrapper(43, this, varargin{:});
varargout{1} = geometry_wrapper(49, this, varargin{:});
return
end
error('Arguments do not match any overload of function Test.return_vector2');

View File

@ -1,6 +1,6 @@
function varargout = aGlobalFunction(varargin)
if length(varargin) == 0
varargout{1} = geometry_wrapper(99, varargin{:});
varargout{1} = geometry_wrapper(105, varargin{:});
else
error('Arguments do not match any overload of function aGlobalFunction');
end

File diff suppressed because it is too large Load Diff

View File

@ -1,10 +1,10 @@
function varargout = load2D(varargin)
if length(varargin) == 5 && isa(varargin{1},'char') && isa(varargin{2},'Test') && isa(varargin{3},'numeric') && isa(varargin{4},'logical') && isa(varargin{5},'logical')
[ varargout{1} varargout{2} ] = geometry_wrapper(96, varargin{:});
[ varargout{1} varargout{2} ] = geometry_wrapper(102, varargin{:});
elseif length(varargin) == 5 && isa(varargin{1},'char') && isa(varargin{2},'gtsam.noiseModel.Diagonal') && isa(varargin{3},'numeric') && isa(varargin{4},'logical') && isa(varargin{5},'logical')
[ varargout{1} varargout{2} ] = geometry_wrapper(97, varargin{:});
[ varargout{1} varargout{2} ] = geometry_wrapper(103, varargin{:});
elseif length(varargin) == 2 && isa(varargin{1},'char') && isa(varargin{2},'gtsam.noiseModel.Diagonal')
[ varargout{1} varargout{2} ] = geometry_wrapper(98, varargin{:});
[ varargout{1} varargout{2} ] = geometry_wrapper(104, varargin{:});
else
error('Arguments do not match any overload of function load2D');
end

View File

@ -1,8 +1,8 @@
function varargout = overloadedGlobalFunction(varargin)
if length(varargin) == 1 && isa(varargin{1},'numeric')
varargout{1} = geometry_wrapper(100, varargin{:});
varargout{1} = geometry_wrapper(106, varargin{:});
elseif length(varargin) == 2 && isa(varargin{1},'numeric') && isa(varargin{2},'double')
varargout{1} = geometry_wrapper(101, varargin{:});
varargout{1} = geometry_wrapper(107, varargin{:});
else
error('Arguments do not match any overload of function overloadedGlobalFunction');
end

View File

@ -35,55 +35,29 @@ PYBIND11_MODULE(geometry_py, m_) {
.def("dim",[](gtsam::Point2* self){return self->dim();})
.def("returnChar",[](gtsam::Point2* self){return self->returnChar();})
.def("argChar",[](gtsam::Point2* self, char a){ self->argChar(a);}, py::arg("a"))
.def("argChar",[](gtsam::Point2* self, std::shared_ptr<char>& a){ self->argChar(a);}, py::arg("a"))
.def("argChar",[](gtsam::Point2* self, char& a){ self->argChar(a);}, py::arg("a"))
.def("argChar",[](gtsam::Point2* self, char* a){ self->argChar(a);}, py::arg("a"))
.def("argChar",[](gtsam::Point2* self, const std::shared_ptr<char>& a){ self->argChar(a);}, py::arg("a"))
.def("argChar",[](gtsam::Point2* self, const char& a){ self->argChar(a);}, py::arg("a"))
.def("argChar",[](gtsam::Point2* self, const char* a){ self->argChar(a);}, py::arg("a"))
.def("argUChar",[](gtsam::Point2* self, unsigned char a){ self->argUChar(a);}, py::arg("a"))
.def("eigenArguments",[](gtsam::Point2* self, const gtsam::Vector& v, const gtsam::Matrix& m){ self->eigenArguments(v, m);}, py::arg("v"), py::arg("m"))
.def("vectorConfusion",[](gtsam::Point2* self){return self->vectorConfusion();})
.def("serialize",
[](gtsam::Point2* self){
return gtsam::serialize(*self);
}
)
.def("deserialize",
[](gtsam::Point2* self, string serialized){
gtsam::deserialize(serialized, *self);
}, py::arg("serialized"))
.def("serialize", [](gtsam::Point2* self){ return gtsam::serialize(*self); })
.def("deserialize", [](gtsam::Point2* self, string serialized){ gtsam::deserialize(serialized, *self); }, py::arg("serialized"))
.def(py::pickle(
[](const gtsam::Point2 &a){ // __getstate__
/* Returns a string that encodes the state of the object */
return py::make_tuple(gtsam::serialize(a));
},
[](py::tuple t){ // __setstate__
gtsam::Point2 obj;
gtsam::deserialize(t[0].cast<std::string>(), obj);
return obj;
}))
;
[](const gtsam::Point2 &a){ /* __getstate__: Returns a string that encodes the state of the object */ return py::make_tuple(gtsam::serialize(a)); },
[](py::tuple t){ /* __setstate__ */ gtsam::Point2 obj; gtsam::deserialize(t[0].cast<std::string>(), obj); return obj; }));
py::class_<gtsam::Point3, std::shared_ptr<gtsam::Point3>>(m_gtsam, "Point3")
.def(py::init<double, double, double>(), py::arg("x"), py::arg("y"), py::arg("z"))
.def("norm",[](gtsam::Point3* self){return self->norm();})
.def("serialize",
[](gtsam::Point3* self){
return gtsam::serialize(*self);
}
)
.def("deserialize",
[](gtsam::Point3* self, string serialized){
gtsam::deserialize(serialized, *self);
}, py::arg("serialized"))
.def("serialize", [](gtsam::Point3* self){ return gtsam::serialize(*self); })
.def("deserialize", [](gtsam::Point3* self, string serialized){ gtsam::deserialize(serialized, *self); }, py::arg("serialized"))
.def(py::pickle(
[](const gtsam::Point3 &a){ // __getstate__
/* Returns a string that encodes the state of the object */
return py::make_tuple(gtsam::serialize(a));
},
[](py::tuple t){ // __setstate__
gtsam::Point3 obj;
gtsam::deserialize(t[0].cast<std::string>(), obj);
return obj;
}))
[](const gtsam::Point3 &a){ /* __getstate__: Returns a string that encodes the state of the object */ return py::make_tuple(gtsam::serialize(a)); },
[](py::tuple t){ /* __setstate__ */ gtsam::Point3 obj; gtsam::deserialize(t[0].cast<std::string>(), obj); return obj; }))
.def_static("staticFunction",[](){return gtsam::Point3::staticFunction();})
.def_static("StaticFunctionRet",[](double z){return gtsam::Point3::StaticFunctionRet(z);}, py::arg("z"));
@ -104,11 +78,11 @@ PYBIND11_MODULE(geometry_py, m_) {
.def("arg_EigenConstRef",[](Test* self, const gtsam::Matrix& value){ self->arg_EigenConstRef(value);}, py::arg("value"))
.def("return_field",[](Test* self, const Test& t){return self->return_field(t);}, py::arg("t"))
.def("return_TestPtr",[](Test* self, const std::shared_ptr<Test>& value){return self->return_TestPtr(value);}, py::arg("value"))
.def("return_Test",[](Test* self,const std::shared_ptr<Test>& value){return self->return_Test(value);}, py::arg("value"))
.def("return_Test",[](Test* self, std::shared_ptr<Test>& value){return self->return_Test(value);}, py::arg("value"))
.def("return_Point2Ptr",[](Test* self, bool value){return self->return_Point2Ptr(value);}, py::arg("value"))
.def("create_ptrs",[](Test* self){return self->create_ptrs();})
.def("create_MixedPtrs",[](Test* self){return self->create_MixedPtrs();})
.def("return_ptrs",[](Test* self,const std::shared_ptr<Test>& p1,const std::shared_ptr<Test>& p2){return self->return_ptrs(p1, p2);}, py::arg("p1"), py::arg("p2"))
.def("return_ptrs",[](Test* self, std::shared_ptr<Test>& p1, std::shared_ptr<Test>& p2){return self->return_ptrs(p1, p2);}, py::arg("p1"), py::arg("p2"))
.def("print_",[](Test* self){ self->print();})
.def("__repr__",
[](const Test &a) {
@ -127,12 +101,12 @@ PYBIND11_MODULE(geometry_py, m_) {
.def("templatedMethodVector",[](MyTemplate<gtsam::Point2>* self, const gtsam::Vector& t){return self->templatedMethod<gtsam::Vector>(t);}, py::arg("t"))
.def("templatedMethodMatrix",[](MyTemplate<gtsam::Point2>* self, const gtsam::Matrix& t){return self->templatedMethod<gtsam::Matrix>(t);}, py::arg("t"))
.def("accept_T",[](MyTemplate<gtsam::Point2>* self, const gtsam::Point2& value){ self->accept_T(value);}, py::arg("value"))
.def("accept_Tptr",[](MyTemplate<gtsam::Point2>* self,const std::shared_ptr<gtsam::Point2>& value){ self->accept_Tptr(value);}, py::arg("value"))
.def("return_Tptr",[](MyTemplate<gtsam::Point2>* self,const std::shared_ptr<gtsam::Point2>& value){return self->return_Tptr(value);}, py::arg("value"))
.def("return_T",[](MyTemplate<gtsam::Point2>* self,const std::shared_ptr<gtsam::Point2>& value){return self->return_T(value);}, py::arg("value"))
.def("accept_Tptr",[](MyTemplate<gtsam::Point2>* self, std::shared_ptr<gtsam::Point2>& value){ self->accept_Tptr(value);}, py::arg("value"))
.def("return_Tptr",[](MyTemplate<gtsam::Point2>* self, std::shared_ptr<gtsam::Point2>& value){return self->return_Tptr(value);}, py::arg("value"))
.def("return_T",[](MyTemplate<gtsam::Point2>* self, gtsam::Point2* value){return self->return_T(value);}, py::arg("value"))
.def("create_ptrs",[](MyTemplate<gtsam::Point2>* self){return self->create_ptrs();})
.def("create_MixedPtrs",[](MyTemplate<gtsam::Point2>* self){return self->create_MixedPtrs();})
.def("return_ptrs",[](MyTemplate<gtsam::Point2>* self,const std::shared_ptr<gtsam::Point2>& p1,const std::shared_ptr<gtsam::Point2>& p2){return self->return_ptrs(p1, p2);}, py::arg("p1"), py::arg("p2"))
.def("return_ptrs",[](MyTemplate<gtsam::Point2>* self, std::shared_ptr<gtsam::Point2>& p1, std::shared_ptr<gtsam::Point2>& p2){return self->return_ptrs(p1, p2);}, py::arg("p1"), py::arg("p2"))
.def_static("Level",[](const gtsam::Point2& K){return MyTemplate<gtsam::Point2>::Level(K);}, py::arg("K"));
py::class_<MyTemplate<gtsam::Matrix>, MyBase, std::shared_ptr<MyTemplate<gtsam::Matrix>>>(m_, "MyTemplateMatrix")
@ -144,7 +118,7 @@ PYBIND11_MODULE(geometry_py, m_) {
.def("accept_T",[](MyTemplate<gtsam::Matrix>* self, const gtsam::Matrix& value){ self->accept_T(value);}, py::arg("value"))
.def("accept_Tptr",[](MyTemplate<gtsam::Matrix>* self, const std::shared_ptr<gtsam::Matrix>& value){ self->accept_Tptr(value);}, py::arg("value"))
.def("return_Tptr",[](MyTemplate<gtsam::Matrix>* self, const std::shared_ptr<gtsam::Matrix>& value){return self->return_Tptr(value);}, py::arg("value"))
.def("return_T",[](MyTemplate<gtsam::Matrix>* self,const std::shared_ptr<gtsam::Matrix>& value){return self->return_T(value);}, py::arg("value"))
.def("return_T",[](MyTemplate<gtsam::Matrix>* self, const gtsam::Matrix* value){return self->return_T(value);}, py::arg("value"))
.def("create_ptrs",[](MyTemplate<gtsam::Matrix>* self){return self->create_ptrs();})
.def("create_MixedPtrs",[](MyTemplate<gtsam::Matrix>* self){return self->create_MixedPtrs();})
.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"))
@ -167,12 +141,15 @@ PYBIND11_MODULE(geometry_py, m_) {
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"));
m_.def("load2D",[]( string filename,const std::shared_ptr<Test>& model, int maxID, bool addNoise, bool smart){return ::load2D(filename, model, maxID, addNoise, smart);}, py::arg("filename"), py::arg("model"), py::arg("maxID"), py::arg("addNoise"), py::arg("smart"));
m_.def("load2D",[](string filename, std::shared_ptr<Test>& model, int maxID, bool addNoise, bool smart){return ::load2D(filename, model, maxID, addNoise, smart);}, py::arg("filename"), py::arg("model"), py::arg("maxID"), py::arg("addNoise"), py::arg("smart"));
m_.def("load2D",[](string filename, const std::shared_ptr<gtsam::noiseModel::Diagonal>& model, int maxID, bool addNoise, bool smart){return ::load2D(filename, model, maxID, addNoise, smart);}, py::arg("filename"), py::arg("model"), py::arg("maxID"), py::arg("addNoise"), py::arg("smart"));
m_.def("load2D",[]( string filename,const std::shared_ptr<gtsam::noiseModel::Diagonal>& model){return ::load2D(filename, model);}, py::arg("filename"), py::arg("model"));
m_.def("load2D",[](string filename, gtsam::noiseModel::Diagonal* model){return ::load2D(filename, model);}, py::arg("filename"), py::arg("model"));
m_.def("aGlobalFunction",[](){return ::aGlobalFunction();});
m_.def("overloadedGlobalFunction",[](int a){return ::overloadedGlobalFunction(a);}, py::arg("a"));
m_.def("overloadedGlobalFunction",[](int a, double b){return ::overloadedGlobalFunction(a, b);}, py::arg("a"), py::arg("b"));
m_.def("MultiTemplatedFunctionStringSize_tDouble",[](const T& x, size_t y){return ::MultiTemplatedFunction<string,size_t,double>(x, y);}, py::arg("x"), py::arg("y"));
m_.def("MultiTemplatedFunctionDoubleSize_tDouble",[](const T& x, size_t y){return ::MultiTemplatedFunction<double,size_t,double>(x, y);}, py::arg("x"), py::arg("y"));
m_.def("TemplatedFunctionRot3",[](const gtsam::Rot3& t){ ::TemplatedFunction<Rot3>(t);}, py::arg("t"));
#include "python/specializations.h"

View File

@ -0,0 +1,62 @@
#include <pybind11/eigen.h>
#include <pybind11/stl_bind.h>
#include <pybind11/pybind11.h>
#include "gtsam/nonlinear/utilities.h" // for RedirectCout.
#include "path/to/ns1.h"
#include "path/to/ns1/ClassB.h"
#include "path/to/ns2.h"
#include "path/to/ns2/ClassA.h"
#include "path/to/ns3.h"
#include "wrap/serialization.h"
#include <boost/serialization/export.hpp>
using namespace std;
namespace py = pybind11;
PYBIND11_MODULE(testNamespaces_py, m_) {
m_.doc() = "pybind11 wrapper of testNamespaces_py";
pybind11::module m_ns1 = m_.def_submodule("ns1", "ns1 submodule");
py::class_<ns1::ClassA, std::shared_ptr<ns1::ClassA>>(m_ns1, "ClassA")
.def(py::init<>());
py::class_<ns1::ClassB, std::shared_ptr<ns1::ClassB>>(m_ns1, "ClassB")
.def(py::init<>());
m_ns1.def("aGlobalFunction",[](){return ns1::aGlobalFunction();}); pybind11::module m_ns2 = m_.def_submodule("ns2", "ns2 submodule");
py::class_<ns2::ClassA, std::shared_ptr<ns2::ClassA>>(m_ns2, "ClassA")
.def(py::init<>())
.def("memberFunction",[](ns2::ClassA* self){return self->memberFunction();})
.def("nsArg",[](ns2::ClassA* self, const ns1::ClassB& arg){return self->nsArg(arg);}, py::arg("arg"))
.def("nsReturn",[](ns2::ClassA* self, double q){return self->nsReturn(q);}, py::arg("q"))
.def_static("afunction",[](){return ns2::ClassA::afunction();});
pybind11::module m_ns2_ns3 = m_ns2.def_submodule("ns3", "ns3 submodule");
py::class_<ns2::ns3::ClassB, std::shared_ptr<ns2::ns3::ClassB>>(m_ns2_ns3, "ClassB")
.def(py::init<>());
py::class_<ns2::ClassC, std::shared_ptr<ns2::ClassC>>(m_ns2, "ClassC")
.def(py::init<>());
m_ns2.def("aGlobalFunction",[](){return ns2::aGlobalFunction();});
m_ns2.def("overloadedGlobalFunction",[](const ns1::ClassA& a){return ns2::overloadedGlobalFunction(a);}, py::arg("a"));
m_ns2.def("overloadedGlobalFunction",[](const ns1::ClassA& a, double b){return ns2::overloadedGlobalFunction(a, b);}, py::arg("a"), py::arg("b"));
py::class_<ClassD, std::shared_ptr<ClassD>>(m_, "ClassD")
.def(py::init<>());
#include "python/specializations.h"
}

View File

@ -17,6 +17,12 @@ class Point2 {
int dim() const;
char returnChar() const;
void argChar(char a) const;
void argChar(char* a) const;
void argChar(char& a) const;
void argChar(char@ a) const;
void argChar(const char* a) const;
void argChar(const char& a) const;
void argChar(const char@ a) const;
void argUChar(unsigned char a) const;
void eigenArguments(Vector v, Matrix m) const;
VectorNotEigen vectorConfusion();
@ -87,7 +93,7 @@ class Test {
bool return_field(const Test& t) const;
Test* return_TestPtr(Test* value) const;
Test* return_TestPtr(const Test* value) const;
Test return_Test(Test* value) const;
gtsam::Point2* return_Point2Ptr(bool value) const;
@ -104,8 +110,8 @@ class Test {
};
pair<gtsam::NonlinearFactorGraph*, gtsam::Values*> load2D(string filename, Test* model, int maxID, bool addNoise, bool smart);
pair<gtsam::NonlinearFactorGraph*, gtsam::Values*> load2D(string filename, gtsam::noiseModel::Diagonal* model, int maxID, bool addNoise, bool smart);
pair<gtsam::NonlinearFactorGraph*, gtsam::Values*> load2D(string filename, gtsam::noiseModel::Diagonal* model);
pair<gtsam::NonlinearFactorGraph*, gtsam::Values*> load2D(string filename, const gtsam::noiseModel::Diagonal* model, int maxID, bool addNoise, bool smart);
pair<gtsam::NonlinearFactorGraph*, gtsam::Values*> load2D(string filename, gtsam::noiseModel::Diagonal@ model);
Vector aGlobalFunction();
@ -130,7 +136,7 @@ virtual class MyTemplate : MyBase {
void accept_T(const T& value) const;
void accept_Tptr(T* value) const;
T* return_Tptr(T* value) const;
T return_T(T* value) const;
T return_T(T@ value) const;
pair<T*,T*> create_ptrs () const;
pair<T ,T*> create_MixedPtrs () const;
pair<T*,T*> return_ptrs (T* p1, T* p2) const;
@ -167,3 +173,13 @@ class MyVector {
// Class with multiple instantiated templates
template<T = {int}, U = {double, float}>
class MultipleTemplates {};
// A templated free/global function. Multiple templates supported.
template<T1 = {string, double}, T2 = {size_t}, R = {double}>
R MultiTemplatedFunction(const T& x, T2 y);
// Check if we can typedef the templated function
template<T>
void TemplatedFunction(const T& t);
typedef TemplatedFunction<gtsam::Rot3> TemplatedFunctionRot3;

View File

@ -1,258 +0,0 @@
# TODO(duy): make them proper tests!!!
import unittest
import sys, os
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
from gtwrap.interface_parser import *
class TestPyparsing(unittest.TestCase):
def test_argument_list(self):
arg_string = "int a, C1 c1, C2& c2, C3* c3, "\
"const C4 c4, const C5& c5,"\
"const C6* c6"
args = ArgumentList.rule.parseString(arg_string)
print(ArgumentList(args))
empty_args = ArgumentList.rule.parseString("")[0]
print(empty_args)
arg_string = "int a, C1 c1, C2& c2, C3* c3, "\
"const C4 c4, const C5& c5,"\
"const C6* c6"
args = ArgumentList.rule.parseString(arg_string)[0]
print(args)
# Test ReturnType
ReturnType.rule.parseString("pair<fdsa, rewcds>")[0]
ReturnType.rule.parseString("cdwdc")[0]
# expect throw
# ReturnType.parseString("int&")
# ReturnType.parseString("const int")
ret = Class.rule.parseString("""
virtual class SymbolicFactorGraph {
SymbolicFactorGraph();
SymbolicFactorGraph(const gtsam::SymbolicBayesNet& bayesNet);
SymbolicFactorGraph(const gtsam::SymbolicBayesTree& bayesTree);
// From FactorGraph.
void push_back(gtsam::SymbolicFactor* factor);
void print(string s) const;
bool equals(const gtsam::SymbolicFactorGraph& rhs, double tol) const;
size_t size() const;
bool exists(size_t idx) const;
// Standard interface
gtsam::KeySet keys() const;
void push_back(const gtsam::SymbolicFactorGraph& graph);
void push_back(const gtsam::SymbolicBayesNet& bayesNet);
void push_back(const gtsam::SymbolicBayesTree& bayesTree);
/* Advanced interface */
void push_factor(size_t key);
void push_factor(size_t key1, size_t key2);
void push_factor(size_t key1, size_t key2, size_t key3);
void push_factor(size_t key1, size_t key2, size_t key3, size_t key4);
gtsam::SymbolicBayesNet* eliminateSequential();
gtsam::SymbolicBayesNet* eliminateSequential(
const gtsam::Ordering& ordering);
gtsam::SymbolicBayesTree* eliminateMultifrontal();
gtsam::SymbolicBayesTree* eliminateMultifrontal(
const gtsam::Ordering& ordering);
pair<gtsam::SymbolicBayesNet*, gtsam::SymbolicFactorGraph*>
eliminatePartialSequential(const gtsam::Ordering& ordering);
pair<gtsam::SymbolicBayesNet*, gtsam::SymbolicFactorGraph*>
eliminatePartialSequential(const gtsam::KeyVector& keys);
pair<gtsam::SymbolicBayesTree*, gtsam::SymbolicFactorGraph*>
eliminatePartialMultifrontal(const gtsam::Ordering& ordering);
gtsam::SymbolicBayesNet* marginalMultifrontalBayesNet(
const gtsam::Ordering& ordering);
gtsam::SymbolicBayesNet* marginalMultifrontalBayesNet(
const gtsam::KeyVector& key_vector,
const gtsam::Ordering& marginalizedVariableOrdering);
gtsam::SymbolicFactorGraph* marginal(const gtsam::KeyVector& key_vector);
};
""")[0]
ret = Class.rule.parseString("""
virtual class Base {
};
""")[0]
ret = Class.rule.parseString("""
virtual class Null: gtsam::noiseModel::mEstimator::Base {
Null();
void print(string s) const;
static gtsam::noiseModel::mEstimator::Null* Create();
// enabling serialization functionality
void serializable() const;
};
""")[0]
retFactorIndices = Class.rule.parseString("""
class FactorIndices {};
""")[0]
retIsam2 = Class.rule.parseString("""
class ISAM2 {
ISAM2();
ISAM2(const gtsam::ISAM2Params& params);
ISAM2(const gtsam::ISAM2& other);
bool equals(const gtsam::ISAM2& other, double tol) const;
void print(string s) const;
void printStats() const;
void saveGraph(string s) const;
gtsam::ISAM2Result update();
gtsam::ISAM2Result update(const gtsam::NonlinearFactorGraph& newFactors,
const gtsam::Values& newTheta);
gtsam::ISAM2Result update(const gtsam::NonlinearFactorGraph& newFactors,
const gtsam::Values& newTheta, const gtsam::FactorIndices&
removeFactorIndices);
gtsam::ISAM2Result update(const gtsam::NonlinearFactorGraph& newFactors,
const gtsam::Values& newTheta,
const gtsam::FactorIndices& removeFactorIndices,
const gtsam::KeyGroupMap& constrainedKeys);
gtsam::Values getLinearizationPoint() const;
gtsam::Values calculateEstimate() const;
template <VALUE = {gtsam::Point2, gtsam::Rot2, gtsam::Pose2, gtsam::Point3,
gtsam::Rot3, gtsam::Pose3, gtsam::Cal3_S2, gtsam::Cal3DS2,
gtsam::Cal3Bundler, gtsam::EssentialMatrix,
gtsam::SimpleCamera, Vector, Matrix}>
VALUE calculateEstimate(size_t key) const;
gtsam::Values calculateBestEstimate() const;
Matrix marginalCovariance(size_t key) const;
gtsam::VectorValues getDelta() const;
gtsam::NonlinearFactorGraph getFactorsUnsafe() const;
gtsam::VariableIndex getVariableIndex() const;
gtsam::ISAM2Params params() const;
};
""")[0]
# if __name__ == '__main__':
# unittest.main()
typename = Typename.rule.parseString("rew")[0]
ret = ReturnType.rule.parseString("pair<fdsa, rewcds>")[0]
ret1 = Method.rule.parseString(
"int f(const int x, const Class& c, Class* t) const;")[0]
ret = Method.rule.parseString("int f() const;")[0]
ret1 = StaticMethod.rule.parseString(
"static int f(const int x, const Class& c, Class* t);")[0]
ret = StaticMethod.rule.parseString("static int f();")[0]
ret1 = Constructor.rule.parseString(
"f(const int x, const Class& c, Class* t);")[0]
ret = Constructor.rule.parseString("f();")[0]
typedef = TypedefTemplateInstantiation.rule.parseString("""
typedef gtsam::BearingFactor<gtsam::Pose2, gtsam::Point2, gtsam::Rot2>
BearingFactor2D;
""")[0]
include = Include.rule.parseString("#include <gtsam/slam/PriorFactor.h>")[0]
print(include)
fwd = ForwardDeclaration.rule.parseString(
"virtual class Test:gtsam::Point3;")[0]
func = GlobalFunction.rule.parseString("""
gtsam::Values localToWorld(const gtsam::Values& local,
const gtsam::Pose2& base, const gtsam::KeyVector& keys);
""")[0]
print(func)
try:
namespace = Namespace.rule.parseString("""
namespace gtsam {
#include <gtsam/geometry/Point2.h>
class Point2 {
Point2();
Point2(double x, double y);
double x() const;
double y() const;
int dim() const;
char returnChar() const;
void argChar(char a) const;
void argUChar(unsigned char a) const;
void eigenArguments(Vector v, Matrix m) const;
VectorNotEigen vectorConfusion();
};
#include <gtsam/geometry/Point3.h>
class Point3 {
Point3(double x, double y, double z);
double norm() const;
// static functions - use static keyword and uppercase
static double staticFunction();
static gtsam::Point3 StaticFunctionRet(double z);
// enabling serialization functionality
void serialize() const; // Just triggers a flag internally
};
}
""")
except ParseException as pe:
print(pe.markInputline())
# filename = "tools/workspace/pybind_wrapper/gtsam.h"
# with open(filename, "r") as f:
# content = f.read()
# module = Module.parseString(content)
module = Module.parseString("""
namespace one {
namespace two {
namespace three {
class Class123 {
};
}
class Class12a {
};
}
namespace two_dummy {
namespace three_dummy{
}
namespace fourth_dummy{
}
}
namespace two {
class Class12b {
};
}
}
class Global{
};
""")
print("module: ", module)
sub_namespace = find_sub_namespace(module, ['one', 'two', 'three'])
print("Found namespace:", sub_namespace[0].name)
print(find_sub_namespace(module, ['one', 'two_test', 'three']))
print(find_sub_namespace(module, ['one', 'two']))
found_class = module.find_class(
Typename(namespaces_name=['one', 'two', 'three', 'Class123']))
print(found_class)
found_class = module.find_class(
Typename(namespaces_name=['one', 'two', 'Class12b']))
print(found_class.name)
found_class = module.find_class(
Typename(namespaces_name=['one', 'two', 'Class12a']))
print(found_class.name)

View File

@ -1,6 +1,6 @@
"""
Unit test for documentation generation
Author: Matthew Sklar
Author: Matthew Sklar, Varun Agrawal
Date: May 2019
"""
import filecmp
@ -16,7 +16,6 @@ sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
import docs.parser.parse_doxygen_xml as parser
from docs.docs import ClassDoc, Doc, Docs, FreeDoc
tree_root = ET.Element('a')
tree_left = ET.SubElement(tree_root, 'b')
tree_right = ET.SubElement(tree_root, 1)
@ -31,6 +30,7 @@ d2 = ET.SubElement(d, 'd')
class TestDocument(unittest.TestCase):
"""Test class for document generation utilities."""
DIR_NAME = path.dirname(__file__)
DOC_DIR = 'doc-test-files'
@ -42,33 +42,39 @@ class TestDocument(unittest.TestCase):
EXPECTED_XML_DIR_PATH = path.abspath(path.join(DIR_NAME, EXPECTED_XML_DIR))
def test_generate_xml(self):
'''Test parse_xml.generate_xml'''
"""Test parse_xml.generate_xml"""
if path.exists(self.OUTPUT_XML_DIR_PATH):
shutil.rmtree(self.OUTPUT_XML_DIR_PATH, ignore_errors=True)
parser.generate_xml(
self.DOC_DIR_PATH, self.OUTPUT_XML_DIR_PATH, quiet=True)
parser.generate_xml(self.DOC_DIR_PATH,
self.OUTPUT_XML_DIR_PATH,
quiet=True)
self.assertTrue(os.path.isdir(self.OUTPUT_XML_DIR_PATH))
shutil.rmtree(path.join(self.OUTPUT_XML_DIR_PATH, 'xml'))
parser.generate_xml(
self.DOC_DIR_PATH, self.OUTPUT_XML_DIR_PATH, quiet=True)
xml_path = path.join(self.OUTPUT_XML_DIR_PATH, 'xml')
if path.exists(xml_path):
shutil.rmtree(xml_path)
parser.generate_xml(self.DOC_DIR_PATH,
self.OUTPUT_XML_DIR_PATH,
quiet=True)
dircmp = filecmp.dircmp(
self.OUTPUT_XML_DIR_PATH, self.EXPECTED_XML_DIR_PATH)
dircmp = filecmp.dircmp(self.OUTPUT_XML_DIR_PATH,
self.EXPECTED_XML_DIR_PATH)
self.assertTrue(not dircmp.diff_files and not dircmp.funny_files)
def test_parse(self):
docs = parser.ParseDoxygenXML(
self.DOC_DIR_PATH, self.OUTPUT_XML_DIR_PATH).run()
"""Test the parsing of the XML generated by Doxygen."""
docs = parser.ParseDoxygenXML(self.DOC_DIR_PATH,
self.OUTPUT_XML_DIR_PATH).run()
for class_name in docs.get_class_docs_keys_list():
actual_tree_root = docs.get_class_docs(
class_name).get_tree().getroot()
expected_tree_root = ET.parse(class_name).getroot()
self.assertEqual(
ET.tostring(actual_tree_root), ET.tostring(expected_tree_root))
self.assertEqual(ET.tostring(actual_tree_root),
ET.tostring(expected_tree_root))
class TestDocTemplate(unittest.TestCase):
@ -102,7 +108,7 @@ class TestDocTemplate(unittest.TestCase):
# ClassDoc
def test_class_doc(self):
'''Test the constructor in ClassDoc'''
"""Test the constructor in ClassDoc"""
self.assertIs(self.class_doc_root.tree, tree_root)
self.assertIs(self.class_doc_left.tree, tree_left)
self.assertIs(self.class_doc_right.tree, tree_right)
@ -110,7 +116,7 @@ class TestDocTemplate(unittest.TestCase):
self.assertIs(self.class_doc_recursive.tree, tree_recursive)
def test_class_doc_get_tree(self):
'''Test the get_tree() method is ClassDoc'''
"""Test the get_tree() method is ClassDoc"""
self.assertIs(self.class_doc_root.get_tree(), tree_root)
self.assertIs(self.class_doc_left.get_tree(), tree_left)
self.assertIs(self.class_doc_right.get_tree(), tree_right)
@ -118,7 +124,7 @@ class TestDocTemplate(unittest.TestCase):
self.assertIs(self.class_doc_recursive.get_tree(), tree_recursive)
def test_class_doc_eq(self):
'''Test ClassDoc.__eq__'''
"""Test ClassDoc.__eq__"""
doc1 = ClassDoc(ET.ElementTree(a))
doc2 = ClassDoc(ET.ElementTree(d))
doc3 = ClassDoc(ET.ElementTree(d2))
@ -132,7 +138,7 @@ class TestDocTemplate(unittest.TestCase):
# FreeDoc
def test_free_doc(self):
'''Test the constructor in FreeDoc'''
"""Test the constructor in FreeDoc"""
self.assertIs(self.free_doc_root.tree, tree_root)
self.assertIs(self.free_doc_left.tree, tree_left)
self.assertIs(self.free_doc_right.tree, tree_right)
@ -140,7 +146,7 @@ class TestDocTemplate(unittest.TestCase):
self.assertIs(self.free_doc_recursive.tree, tree_recursive)
def test_free_doc_get_tree(self):
'''Test the get_tree() method is FreeDoc'''
"""Test the get_tree() method is FreeDoc"""
self.assertIs(self.free_doc_root.get_tree(), tree_root)
self.assertIs(self.free_doc_left.get_tree(), tree_left)
self.assertIs(self.free_doc_right.get_tree(), tree_right)
@ -148,7 +154,7 @@ class TestDocTemplate(unittest.TestCase):
self.assertIs(self.free_doc_recursive.get_tree(), tree_recursive)
def test_free_doc_eq(self):
'''Test FreeDoc.__eq__'''
"""Test FreeDoc.__eq__"""
doc1 = FreeDoc(ET.ElementTree(a))
doc2 = FreeDoc(ET.ElementTree(d))
doc3 = FreeDoc(ET.ElementTree(d2))
@ -162,7 +168,7 @@ class TestDocTemplate(unittest.TestCase):
# Docs
def test_docs(self):
'''Test Docs template constructor'''
"""Test Docs template constructor"""
docs = Docs(self.CLASS_DOCS, self.FREE_DOCS)
self.assertIs(docs.class_docs, self.CLASS_DOCS)
@ -172,15 +178,15 @@ class TestDocTemplate(unittest.TestCase):
docs = Docs(self.CLASS_DOCS, self.FREE_DOCS)
for doc_name in self.CLASS_DOCS.keys():
self.assertIs(
self.CLASS_DOCS.get(doc_name), docs.get_class_docs(doc_name))
self.assertIs(self.CLASS_DOCS.get(doc_name),
docs.get_class_docs(doc_name))
def test_get_free_docs(self):
docs = Docs(self.CLASS_DOCS, self.FREE_DOCS)
for doc_name in self.FREE_DOCS.keys():
self.assertIs(
self.FREE_DOCS.get(doc_name), docs.get_free_docs(doc_name))
self.assertIs(self.FREE_DOCS.get(doc_name),
docs.get_free_docs(doc_name))
def test_get_class_docs_keys_list(self):
docs = Docs(self.CLASS_DOCS, self.FREE_DOCS)

View File

@ -0,0 +1,372 @@
"""
GTSAM Copyright 2010-2020, Georgia Tech Research Corporation,
Atlanta, Georgia 30332-0415
All Rights Reserved
See LICENSE for the license information
Tests for interface_parser.
Author: Varun Agrawal
"""
# pylint: disable=import-error,wrong-import-position
import os
import sys
import unittest
from pyparsing import ParseException
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
from gtwrap.interface_parser import (ArgumentList, Class, Constructor,
ForwardDeclaration, GlobalFunction,
Include, Method, Module, Namespace,
ReturnType, StaticMethod, Type,
TypedefTemplateInstantiation, Typename,
find_sub_namespace)
class TestInterfaceParser(unittest.TestCase):
"""Test driver for all classes in interface_parser.py."""
def test_typename(self):
"""Test parsing of Typename."""
typename = Typename.rule.parseString("size_t")[0]
self.assertEqual("size_t", typename.name)
typename = Typename.rule.parseString("gtsam::PinholeCamera<gtsam::Cal3S2>")[0]
self.assertEqual("PinholeCamera", typename.name)
self.assertEqual(["gtsam"], typename.namespaces)
self.assertEqual("Cal3S2", typename.instantiations[0].name)
self.assertEqual(["gtsam"], typename.instantiations[0].namespaces)
def test_type(self):
"""Test for Type."""
t = Type.rule.parseString("int x")[0]
self.assertEqual("int", t.typename.name)
self.assertTrue(t.is_basis)
t = Type.rule.parseString("T x")[0]
self.assertEqual("T", t.typename.name)
self.assertTrue(not t.is_basis)
t = Type.rule.parseString("const int x")[0]
self.assertEqual("int", t.typename.name)
self.assertTrue(t.is_basis)
self.assertTrue(t.is_const)
def test_empty_arguments(self):
"""Test no arguments."""
empty_args = ArgumentList.rule.parseString("")[0]
self.assertEqual(0, len(empty_args))
def test_argument_list(self):
"""Test arguments list for a method/function."""
arg_string = "int a, C1 c1, C2& c2, C3* c3, "\
"const C4 c4, const C5& c5,"\
"const C6* c6"
args = ArgumentList.rule.parseString(arg_string)[0]
self.assertEqual(7, len(args.args_list))
self.assertEqual(['a', 'c1', 'c2', 'c3', 'c4', 'c5', 'c6'],
args.args_names())
def test_argument_list_qualifiers(self):
"""
Test arguments list where the arguments are qualified with `const`
and can be either raw pointers, shared pointers or references.
"""
arg_string = "double x1, double* x2, double& x3, double@ x4, " \
"const double x5, const double* x6, const double& x7, const double@ x8"
args = ArgumentList.rule.parseString(arg_string)[0].args_list
self.assertEqual(8, len(args))
self.assertFalse(args[1].ctype.is_ptr and args[1].ctype.is_shared_ptr
and args[1].ctype.is_ref)
self.assertTrue(args[1].ctype.is_shared_ptr)
self.assertTrue(args[2].ctype.is_ref)
self.assertTrue(args[3].ctype.is_ptr)
self.assertTrue(args[4].ctype.is_const)
self.assertTrue(args[5].ctype.is_shared_ptr and args[5].ctype.is_const)
self.assertTrue(args[6].ctype.is_ref and args[6].ctype.is_const)
self.assertTrue(args[7].ctype.is_ptr and args[7].ctype.is_const)
def test_return_type(self):
"""Test ReturnType"""
# Test void
return_type = ReturnType.rule.parseString("void")[0]
self.assertEqual("void", return_type.type1.typename.name)
self.assertTrue(return_type.type1.is_basis)
# Test basis type
return_type = ReturnType.rule.parseString("size_t")[0]
self.assertEqual("size_t", return_type.type1.typename.name)
self.assertTrue(not return_type.type2)
self.assertTrue(return_type.type1.is_basis)
# Test with qualifiers
return_type = ReturnType.rule.parseString("int&")[0]
self.assertEqual("int", return_type.type1.typename.name)
self.assertTrue(return_type.type1.is_basis
and return_type.type1.is_ref)
return_type = ReturnType.rule.parseString("const int")[0]
self.assertEqual("int", return_type.type1.typename.name)
self.assertTrue(return_type.type1.is_basis
and return_type.type1.is_const)
# Test pair return
return_type = ReturnType.rule.parseString("pair<char, int>")[0]
self.assertEqual("char", return_type.type1.typename.name)
self.assertEqual("int", return_type.type2.typename.name)
def test_method(self):
"""Test for a class method."""
ret = Method.rule.parseString("int f();")[0]
self.assertEqual("f", ret.name)
self.assertEqual(0, len(ret.args))
self.assertTrue(not ret.is_const)
ret = Method.rule.parseString("int f() const;")[0]
self.assertEqual("f", ret.name)
self.assertEqual(0, len(ret.args))
self.assertTrue(ret.is_const)
ret = Method.rule.parseString(
"int f(const int x, const Class& c, Class* t) const;")[0]
self.assertEqual("f", ret.name)
self.assertEqual(3, len(ret.args))
def test_static_method(self):
"""Test for static methods."""
ret = StaticMethod.rule.parseString("static int f();")[0]
self.assertEqual("f", ret.name)
self.assertEqual(0, len(ret.args))
ret = StaticMethod.rule.parseString(
"static int f(const int x, const Class& c, Class* t);")[0]
self.assertEqual("f", ret.name)
self.assertEqual(3, len(ret.args))
def test_constructor(self):
"""Test for class constructor."""
ret = Constructor.rule.parseString("f();")[0]
self.assertEqual("f", ret.name)
self.assertEqual(0, len(ret.args))
ret = Constructor.rule.parseString(
"f(const int x, const Class& c, Class* t);")[0]
self.assertEqual("f", ret.name)
self.assertEqual(3, len(ret.args))
def test_typedef_template_instantiation(self):
"""Test for typedef'd instantiation of a template."""
typedef = TypedefTemplateInstantiation.rule.parseString("""
typedef gtsam::BearingFactor<gtsam::Pose2, gtsam::Point2, gtsam::Rot2>
BearingFactor2D;
""")[0]
self.assertEqual("BearingFactor2D", typedef.new_name)
self.assertEqual("BearingFactor", typedef.typename.name)
self.assertEqual(["gtsam"], typedef.typename.namespaces)
self.assertEqual(3, len(typedef.typename.instantiations))
def test_base_class(self):
"""Test a base class."""
ret = Class.rule.parseString("""
virtual class Base {
};
""")[0]
self.assertEqual("Base", ret.name)
self.assertEqual(0, len(ret.ctors))
self.assertEqual(0, len(ret.methods))
self.assertEqual(0, len(ret.static_methods))
self.assertEqual(0, len(ret.properties))
self.assertTrue(ret.is_virtual)
def test_empty_class(self):
"""Test an empty class declaration."""
ret = Class.rule.parseString("""
class FactorIndices {};
""")[0]
self.assertEqual("FactorIndices", ret.name)
self.assertEqual(0, len(ret.ctors))
self.assertEqual(0, len(ret.methods))
self.assertEqual(0, len(ret.static_methods))
self.assertEqual(0, len(ret.properties))
self.assertTrue(not ret.is_virtual)
def test_class(self):
"""Test a non-trivial class."""
ret = Class.rule.parseString("""
class SymbolicFactorGraph {
SymbolicFactorGraph();
SymbolicFactorGraph(const gtsam::SymbolicBayesNet& bayesNet);
SymbolicFactorGraph(const gtsam::SymbolicBayesTree& bayesTree);
// Dummy static method
static gtsam::SymbolidFactorGraph CreateGraph();
void push_back(gtsam::SymbolicFactor* factor);
void print(string s) const;
bool equals(const gtsam::SymbolicFactorGraph& rhs, double tol) const;
size_t size() const;
bool exists(size_t idx) const;
// Standard interface
gtsam::KeySet keys() const;
void push_back(const gtsam::SymbolicFactorGraph& graph);
void push_back(const gtsam::SymbolicBayesNet& bayesNet);
void push_back(const gtsam::SymbolicBayesTree& bayesTree);
/* Advanced interface */
void push_factor(size_t key);
void push_factor(size_t key1, size_t key2);
void push_factor(size_t key1, size_t key2, size_t key3);
void push_factor(size_t key1, size_t key2, size_t key3, size_t key4);
gtsam::SymbolicBayesNet* eliminateSequential();
gtsam::SymbolicBayesNet* eliminateSequential(
const gtsam::Ordering& ordering);
gtsam::SymbolicBayesTree* eliminateMultifrontal();
gtsam::SymbolicBayesTree* eliminateMultifrontal(
const gtsam::Ordering& ordering);
pair<gtsam::SymbolicBayesNet*, gtsam::SymbolicFactorGraph*>
eliminatePartialSequential(const gtsam::Ordering& ordering);
pair<gtsam::SymbolicBayesNet*, gtsam::SymbolicFactorGraph*>
eliminatePartialSequential(const gtsam::KeyVector& keys);
pair<gtsam::SymbolicBayesTree*, gtsam::SymbolicFactorGraph*>
eliminatePartialMultifrontal(const gtsam::Ordering& ordering);
gtsam::SymbolicBayesNet* marginalMultifrontalBayesNet(
const gtsam::Ordering& ordering);
gtsam::SymbolicBayesNet* marginalMultifrontalBayesNet(
const gtsam::KeyVector& key_vector,
const gtsam::Ordering& marginalizedVariableOrdering);
gtsam::SymbolicFactorGraph* marginal(const gtsam::KeyVector& key_vector);
};
""")[0]
self.assertEqual("SymbolicFactorGraph", ret.name)
self.assertEqual(3, len(ret.ctors))
self.assertEqual(23, len(ret.methods))
self.assertEqual(1, len(ret.static_methods))
self.assertEqual(0, len(ret.properties))
self.assertTrue(not ret.is_virtual)
def test_class_inheritance(self):
"""Test for class inheritance."""
ret = Class.rule.parseString("""
virtual class Null: gtsam::noiseModel::mEstimator::Base {
Null();
void print(string s) const;
static gtsam::noiseModel::mEstimator::Null* Create();
// enabling serialization functionality
void serializable() const;
};
""")[0]
self.assertEqual("Null", ret.name)
self.assertEqual(1, len(ret.ctors))
self.assertEqual(2, len(ret.methods))
self.assertEqual(1, len(ret.static_methods))
self.assertEqual(0, len(ret.properties))
self.assertEqual("Base", ret.parent_class.name)
self.assertEqual(["gtsam", "noiseModel", "mEstimator"],
ret.parent_class.namespaces)
self.assertTrue(ret.is_virtual)
def test_include(self):
"""Test for include statements."""
include = Include.rule.parseString(
"#include <gtsam/slam/PriorFactor.h>")[0]
self.assertEqual("gtsam/slam/PriorFactor.h", include.header)
def test_forward_declaration(self):
"""Test for forward declarations."""
fwd = ForwardDeclaration.rule.parseString(
"virtual class Test:gtsam::Point3;")[0]
fwd_name = fwd.name.asList()[0]
self.assertEqual("Test", fwd_name.name)
self.assertTrue(fwd.is_virtual)
def test_function(self):
"""Test for global/free function."""
func = GlobalFunction.rule.parseString("""
gtsam::Values localToWorld(const gtsam::Values& local,
const gtsam::Pose2& base, const gtsam::KeyVector& keys);
""")[0]
self.assertEqual("localToWorld", func.name)
self.assertEqual("Values", func.return_type.type1.typename.name)
self.assertEqual(3, len(func.args))
def test_namespace(self):
"""Test for namespace parsing."""
namespace = Namespace.rule.parseString("""
namespace gtsam {
#include <gtsam/geometry/Point2.h>
class Point2 {
Point2();
Point2(double x, double y);
double x() const;
double y() const;
int dim() const;
char returnChar() const;
void argChar(char a) const;
void argUChar(unsigned char a) const;
};
#include <gtsam/geometry/Point3.h>
class Point3 {
Point3(double x, double y, double z);
double norm() const;
// static functions - use static keyword and uppercase
static double staticFunction();
static gtsam::Point3 StaticFunctionRet(double z);
// enabling serialization functionality
void serialize() const; // Just triggers a flag internally
};
}""")[0]
self.assertEqual("gtsam", namespace.name)
def test_module(self):
"""Test module parsing."""
module = Module.parseString("""
namespace one {
namespace two {
namespace three {
class Class123 {
};
}
class Class12a {
};
}
namespace two_dummy {
namespace three_dummy{
}
namespace fourth_dummy{
}
}
namespace two {
class Class12b {
};
}
}
class Global{
};
""")
# print("module: ", module)
# print(dir(module.content[0].name))
self.assertEqual(["one", "Global"], [x.name for x in module.content])
self.assertEqual(["two", "two_dummy", "two"],
[x.name for x in module.content[0].content])
if __name__ == '__main__':
unittest.main()

View File

@ -10,6 +10,8 @@ import os
import sys
import unittest
from loguru import logger
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
import gtwrap.interface_parser as parser
@ -25,6 +27,10 @@ class TestWrap(unittest.TestCase):
MATLAB_TEST_DIR = TEST_DIR + "expected-matlab/"
MATLAB_ACTUAL_DIR = TEST_DIR + "actual-matlab/"
# set the log level to INFO by default
logger.remove() # remove the default sink
logger.add(sys.stderr, format="{time} {level} {message}", level="INFO")
def generate_content(self, cc_content, path=''):
"""Generate files and folders from matlab wrapper content.
@ -41,7 +47,7 @@ class TestWrap(unittest.TestCase):
if isinstance(c, list):
if len(c) == 0:
continue
print("c object: {}".format(c[0][0]), file=sys.stderr)
logger.debug("c object: {}".format(c[0][0]))
path_to_folder = path + '/' + c[0][0]
if not os.path.isdir(path_to_folder):
@ -51,13 +57,13 @@ class TestWrap(unittest.TestCase):
pass
for sub_content in c:
print("sub object: {}".format(sub_content[1][0][0]), file=sys.stderr)
logger.debug("sub object: {}".format(sub_content[1][0][0]))
self.generate_content(sub_content[1], path_to_folder)
elif isinstance(c[1], list):
path_to_folder = path + '/' + c[0]
print("[generate_content_global]: {}".format(path_to_folder), file=sys.stderr)
logger.debug("[generate_content_global]: {}".format(path_to_folder))
if not os.path.isdir(path_to_folder):
try:
os.makedirs(path_to_folder, exist_ok=True)
@ -65,14 +71,15 @@ class TestWrap(unittest.TestCase):
pass
for sub_content in c[1]:
path_to_file = path_to_folder + '/' + sub_content[0]
print("[generate_global_method]: {}".format(path_to_file), file=sys.stderr)
logger.debug(
"[generate_global_method]: {}".format(path_to_file))
with open(path_to_file, 'w') as f:
f.write(sub_content[1])
else:
path_to_file = path + '/' + c[0]
print("[generate_content]: {}".format(path_to_file), file=sys.stderr)
logger.debug("[generate_content]: {}".format(path_to_file))
if not os.path.isdir(path_to_file):
try:
os.mkdir(path)
@ -122,23 +129,16 @@ class TestWrap(unittest.TestCase):
self.assertTrue(os.path.isdir(self.MATLAB_ACTUAL_DIR + '+gtsam'))
files = [
'+gtsam/Point2.m',
'+gtsam/Point3.m',
'Test.m',
'MyBase.m',
'load2D.m',
'MyTemplatePoint2.m',
'MyTemplateMatrix.m',
'MyVector3.m',
'MyVector12.m',
'MyFactorPosePoint2.m',
'aGlobalFunction.m',
'overloadedGlobalFunction.m',
'+gtsam/Point2.m', '+gtsam/Point3.m', 'Test.m', 'MyBase.m',
'load2D.m', 'MyTemplatePoint2.m', 'MyTemplateMatrix.m',
'MyVector3.m', 'MyVector12.m', 'MyFactorPosePoint2.m',
'aGlobalFunction.m', 'overloadedGlobalFunction.m',
'geometry_wrapper.cpp'
]
for file in files:
compare_and_diff(file)
if __name__ == '__main__':
unittest.main()

View File

@ -26,15 +26,10 @@ class TestWrap(unittest.TestCase):
"""Tests for Python wrapper based on Pybind11."""
TEST_DIR = os.path.dirname(os.path.realpath(__file__)) + "/"
def test_geometry_python(self):
def wrap_content(self, content, module_name, output_dir):
"""
Check generation of python geometry wrapper.
python3 ../pybind_wrapper.py --src geometry.h --module_name
geometry_py --out output/geometry_py.cc"
Common function to wrap content.
"""
with open(os.path.join(self.TEST_DIR, 'geometry.h'), 'r') as f:
content = f.read()
module = parser.Module.parseString(content)
instantiator.instantiate_namespace_inplace(module)
@ -45,7 +40,7 @@ class TestWrap(unittest.TestCase):
# Create Pybind wrapper instance
wrapper = PybindWrapper(
module=module,
module_name='geometry_py',
module_name=module_name,
use_boost=False,
top_module_namespaces=[''],
ignore_classes=[''],
@ -54,14 +49,27 @@ class TestWrap(unittest.TestCase):
cc_content = wrapper.wrap()
output = path.join(self.TEST_DIR, 'actual-python/geometry_py.cpp')
output = path.join(self.TEST_DIR, output_dir, module_name + ".cpp")
if not path.exists(path.join(self.TEST_DIR, 'actual-python')):
os.mkdir(path.join(self.TEST_DIR, 'actual-python'))
if not path.exists(path.join(self.TEST_DIR, output_dir)):
os.mkdir(path.join(self.TEST_DIR, output_dir))
with open(output, 'w') as f:
f.write(cc_content)
return output
def test_geometry_python(self):
"""
Check generation of python geometry wrapper.
python3 ../pybind_wrapper.py --src geometry.h --module_name
geometry_py --out output/geometry_py.cc
"""
with open(os.path.join(self.TEST_DIR, 'geometry.h'), 'r') as f:
content = f.read()
output = self.wrap_content(content, 'geometry_py', 'actual-python')
expected = path.join(self.TEST_DIR, 'expected-python/geometry_pybind.cpp')
success = filecmp.cmp(output, expected)
@ -69,5 +77,23 @@ class TestWrap(unittest.TestCase):
os.system("diff {} {}".format(output, expected))
self.assertTrue(success)
def test_namespaces(self):
"""
Check generation of python geometry wrapper.
python3 ../pybind_wrapper.py --src testNamespaces.h --module_name
testNamespaces_py --out output/testNamespaces_py.cc
"""
with open(os.path.join(self.TEST_DIR, 'testNamespaces.h'), 'r') as f:
content = f.read()
output = self.wrap_content(content, 'testNamespaces_py', 'actual-python')
expected = path.join(self.TEST_DIR, 'expected-python/testNamespaces_py.cpp')
success = filecmp.cmp(output, expected)
if not success:
os.system("diff {} {}".format(output, expected))
self.assertTrue(success)
if __name__ == '__main__':
unittest.main()