Add pybind11 2.5 source
This commit is contained in:
parent
e6991ad5dc
commit
444e535f00
70
3rdparty/pybind11/.appveyor.yml
vendored
Normal file
70
3rdparty/pybind11/.appveyor.yml
vendored
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
version: 1.0.{build}
|
||||||
|
image:
|
||||||
|
- Visual Studio 2017
|
||||||
|
- Visual Studio 2015
|
||||||
|
test: off
|
||||||
|
skip_branch_with_pr: true
|
||||||
|
build:
|
||||||
|
parallel: true
|
||||||
|
platform:
|
||||||
|
- x64
|
||||||
|
- x86
|
||||||
|
environment:
|
||||||
|
matrix:
|
||||||
|
- PYTHON: 36
|
||||||
|
CPP: 14
|
||||||
|
CONFIG: Debug
|
||||||
|
- PYTHON: 27
|
||||||
|
CPP: 14
|
||||||
|
CONFIG: Debug
|
||||||
|
- CONDA: 36
|
||||||
|
CPP: latest
|
||||||
|
CONFIG: Release
|
||||||
|
matrix:
|
||||||
|
exclude:
|
||||||
|
- image: Visual Studio 2015
|
||||||
|
platform: x86
|
||||||
|
- image: Visual Studio 2015
|
||||||
|
CPP: latest
|
||||||
|
- image: Visual Studio 2017
|
||||||
|
CPP: latest
|
||||||
|
platform: x86
|
||||||
|
install:
|
||||||
|
- ps: |
|
||||||
|
if ($env:PLATFORM -eq "x64") { $env:CMAKE_ARCH = "x64" }
|
||||||
|
if ($env:APPVEYOR_JOB_NAME -like "*Visual Studio 2017*") {
|
||||||
|
$env:CMAKE_GENERATOR = "Visual Studio 15 2017"
|
||||||
|
$env:CMAKE_INCLUDE_PATH = "C:\Libraries\boost_1_64_0"
|
||||||
|
$env:CXXFLAGS = "-permissive-"
|
||||||
|
} else {
|
||||||
|
$env:CMAKE_GENERATOR = "Visual Studio 14 2015"
|
||||||
|
}
|
||||||
|
if ($env:PYTHON) {
|
||||||
|
if ($env:PLATFORM -eq "x64") { $env:PYTHON = "$env:PYTHON-x64" }
|
||||||
|
$env:PATH = "C:\Python$env:PYTHON\;C:\Python$env:PYTHON\Scripts\;$env:PATH"
|
||||||
|
python -W ignore -m pip install --upgrade pip wheel
|
||||||
|
python -W ignore -m pip install pytest numpy --no-warn-script-location
|
||||||
|
} elseif ($env:CONDA) {
|
||||||
|
if ($env:CONDA -eq "27") { $env:CONDA = "" }
|
||||||
|
if ($env:PLATFORM -eq "x64") { $env:CONDA = "$env:CONDA-x64" }
|
||||||
|
$env:PATH = "C:\Miniconda$env:CONDA\;C:\Miniconda$env:CONDA\Scripts\;$env:PATH"
|
||||||
|
$env:PYTHONHOME = "C:\Miniconda$env:CONDA"
|
||||||
|
conda --version
|
||||||
|
conda install -y -q pytest numpy scipy
|
||||||
|
}
|
||||||
|
- ps: |
|
||||||
|
Start-FileDownload 'http://bitbucket.org/eigen/eigen/get/3.3.3.zip'
|
||||||
|
7z x 3.3.3.zip -y > $null
|
||||||
|
$env:CMAKE_INCLUDE_PATH = "eigen-eigen-67e894c6cd8f;$env:CMAKE_INCLUDE_PATH"
|
||||||
|
build_script:
|
||||||
|
- cmake -G "%CMAKE_GENERATOR%" -A "%CMAKE_ARCH%"
|
||||||
|
-DPYBIND11_CPP_STANDARD=/std:c++%CPP%
|
||||||
|
-DPYBIND11_WERROR=ON
|
||||||
|
-DDOWNLOAD_CATCH=ON
|
||||||
|
-DCMAKE_SUPPRESS_REGENERATION=1
|
||||||
|
.
|
||||||
|
- set MSBuildLogger="C:\Program Files\AppVeyor\BuildAgent\Appveyor.MSBuildLogger.dll"
|
||||||
|
- cmake --build . --config %CONFIG% --target pytest -- /m /v:m /logger:%MSBuildLogger%
|
||||||
|
- cmake --build . --config %CONFIG% --target cpptest -- /m /v:m /logger:%MSBuildLogger%
|
||||||
|
- if "%CPP%"=="latest" (cmake --build . --config %CONFIG% --target test_cmake_build -- /m /v:m /logger:%MSBuildLogger%)
|
||||||
|
on_failure: if exist "tests\test_cmake_build" type tests\test_cmake_build\*.log*
|
38
3rdparty/pybind11/.gitignore
vendored
Normal file
38
3rdparty/pybind11/.gitignore
vendored
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
CMakeCache.txt
|
||||||
|
CMakeFiles
|
||||||
|
Makefile
|
||||||
|
cmake_install.cmake
|
||||||
|
.DS_Store
|
||||||
|
*.so
|
||||||
|
*.pyd
|
||||||
|
*.dll
|
||||||
|
*.sln
|
||||||
|
*.sdf
|
||||||
|
*.opensdf
|
||||||
|
*.vcxproj
|
||||||
|
*.filters
|
||||||
|
example.dir
|
||||||
|
Win32
|
||||||
|
x64
|
||||||
|
Release
|
||||||
|
Debug
|
||||||
|
.vs
|
||||||
|
CTestTestfile.cmake
|
||||||
|
Testing
|
||||||
|
autogen
|
||||||
|
MANIFEST
|
||||||
|
/.ninja_*
|
||||||
|
/*.ninja
|
||||||
|
/docs/.build
|
||||||
|
*.py[co]
|
||||||
|
*.egg-info
|
||||||
|
*~
|
||||||
|
.*.swp
|
||||||
|
.DS_Store
|
||||||
|
/dist
|
||||||
|
/build
|
||||||
|
/cmake/
|
||||||
|
.cache/
|
||||||
|
sosize-*.txt
|
||||||
|
pybind11Config*.cmake
|
||||||
|
pybind11Targets.cmake
|
3
3rdparty/pybind11/.gitmodules
vendored
Normal file
3
3rdparty/pybind11/.gitmodules
vendored
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
[submodule "tools/clang"]
|
||||||
|
path = tools/clang
|
||||||
|
url = ../../wjakob/clang-cindex-python3
|
3
3rdparty/pybind11/.readthedocs.yml
vendored
Normal file
3
3rdparty/pybind11/.readthedocs.yml
vendored
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
python:
|
||||||
|
version: 3
|
||||||
|
requirements_file: docs/requirements.txt
|
306
3rdparty/pybind11/.travis.yml
vendored
Normal file
306
3rdparty/pybind11/.travis.yml
vendored
Normal file
@ -0,0 +1,306 @@
|
|||||||
|
language: cpp
|
||||||
|
matrix:
|
||||||
|
include:
|
||||||
|
# This config does a few things:
|
||||||
|
# - Checks C++ and Python code styles (check-style.sh and flake8).
|
||||||
|
# - Makes sure sphinx can build the docs without any errors or warnings.
|
||||||
|
# - Tests setup.py sdist and install (all header files should be present).
|
||||||
|
# - Makes sure that everything still works without optional deps (numpy/scipy/eigen) and
|
||||||
|
# also tests the automatic discovery functions in CMake (Python version, C++ standard).
|
||||||
|
- os: linux
|
||||||
|
dist: xenial # Necessary to run doxygen 1.8.15
|
||||||
|
name: Style, docs, and pip
|
||||||
|
cache: false
|
||||||
|
before_install:
|
||||||
|
- pyenv global $(pyenv whence 2to3) # activate all python versions
|
||||||
|
- PY_CMD=python3
|
||||||
|
- $PY_CMD -m pip install --user --upgrade pip wheel setuptools
|
||||||
|
install:
|
||||||
|
# breathe 4.14 doesn't work with bit fields. See https://github.com/michaeljones/breathe/issues/462
|
||||||
|
- $PY_CMD -m pip install --user --upgrade sphinx sphinx_rtd_theme breathe==4.13.1 flake8 pep8-naming pytest
|
||||||
|
- curl -fsSL https://sourceforge.net/projects/doxygen/files/rel-1.8.15/doxygen-1.8.15.linux.bin.tar.gz/download | tar xz
|
||||||
|
- export PATH="$PWD/doxygen-1.8.15/bin:$PATH"
|
||||||
|
script:
|
||||||
|
- tools/check-style.sh
|
||||||
|
- flake8
|
||||||
|
- $PY_CMD -m sphinx -W -b html docs docs/.build
|
||||||
|
- |
|
||||||
|
# Make sure setup.py distributes and installs all the headers
|
||||||
|
$PY_CMD setup.py sdist
|
||||||
|
$PY_CMD -m pip install --user -U ./dist/*
|
||||||
|
installed=$($PY_CMD -c "import pybind11; print(pybind11.get_include(True) + '/pybind11')")
|
||||||
|
diff -rq $installed ./include/pybind11
|
||||||
|
- |
|
||||||
|
# Barebones build
|
||||||
|
cmake -DCMAKE_BUILD_TYPE=Debug -DPYBIND11_WERROR=ON -DDOWNLOAD_CATCH=ON -DPYTHON_EXECUTABLE=$(which $PY_CMD) .
|
||||||
|
make pytest -j 2 && make cpptest -j 2
|
||||||
|
# The following are regular test configurations, including optional dependencies.
|
||||||
|
# With regard to each other they differ in Python version, C++ standard and compiler.
|
||||||
|
- os: linux
|
||||||
|
dist: trusty
|
||||||
|
name: Python 2.7, c++11, gcc 4.8
|
||||||
|
env: PYTHON=2.7 CPP=11 GCC=4.8
|
||||||
|
addons:
|
||||||
|
apt:
|
||||||
|
packages:
|
||||||
|
- cmake=2.\*
|
||||||
|
- cmake-data=2.\*
|
||||||
|
- os: linux
|
||||||
|
dist: trusty
|
||||||
|
name: Python 3.6, c++11, gcc 4.8
|
||||||
|
env: PYTHON=3.6 CPP=11 GCC=4.8
|
||||||
|
addons:
|
||||||
|
apt:
|
||||||
|
sources:
|
||||||
|
- deadsnakes
|
||||||
|
packages:
|
||||||
|
- python3.6-dev
|
||||||
|
- python3.6-venv
|
||||||
|
- cmake=2.\*
|
||||||
|
- cmake-data=2.\*
|
||||||
|
- os: linux
|
||||||
|
dist: trusty
|
||||||
|
env: PYTHON=2.7 CPP=14 GCC=6 CMAKE=1
|
||||||
|
name: Python 2.7, c++14, gcc 6, CMake test
|
||||||
|
addons:
|
||||||
|
apt:
|
||||||
|
sources:
|
||||||
|
- ubuntu-toolchain-r-test
|
||||||
|
packages:
|
||||||
|
- g++-6
|
||||||
|
- os: linux
|
||||||
|
dist: trusty
|
||||||
|
name: Python 3.5, c++14, gcc 6, Debug build
|
||||||
|
# N.B. `ensurepip` could be installed transitively by `python3.5-venv`, but
|
||||||
|
# seems to have apt conflicts (at least for Trusty). Use Docker instead.
|
||||||
|
services: docker
|
||||||
|
env: DOCKER=debian:stretch PYTHON=3.5 CPP=14 GCC=6 DEBUG=1
|
||||||
|
- os: linux
|
||||||
|
dist: xenial
|
||||||
|
env: PYTHON=3.6 CPP=17 GCC=7
|
||||||
|
name: Python 3.6, c++17, gcc 7
|
||||||
|
addons:
|
||||||
|
apt:
|
||||||
|
sources:
|
||||||
|
- deadsnakes
|
||||||
|
- ubuntu-toolchain-r-test
|
||||||
|
packages:
|
||||||
|
- g++-7
|
||||||
|
- python3.6-dev
|
||||||
|
- python3.6-venv
|
||||||
|
- os: linux
|
||||||
|
dist: xenial
|
||||||
|
env: PYTHON=3.6 CPP=17 CLANG=7
|
||||||
|
name: Python 3.6, c++17, Clang 7
|
||||||
|
addons:
|
||||||
|
apt:
|
||||||
|
sources:
|
||||||
|
- deadsnakes
|
||||||
|
- llvm-toolchain-xenial-7
|
||||||
|
packages:
|
||||||
|
- python3.6-dev
|
||||||
|
- python3.6-venv
|
||||||
|
- clang-7
|
||||||
|
- libclang-7-dev
|
||||||
|
- llvm-7-dev
|
||||||
|
- lld-7
|
||||||
|
- libc++-7-dev
|
||||||
|
- libc++abi-7-dev # Why is this necessary???
|
||||||
|
- os: linux
|
||||||
|
dist: xenial
|
||||||
|
env: PYTHON=3.8 CPP=17 GCC=7
|
||||||
|
name: Python 3.8, c++17, gcc 7 (w/o numpy/scipy) # TODO: update build name when the numpy/scipy wheels become available
|
||||||
|
addons:
|
||||||
|
apt:
|
||||||
|
sources:
|
||||||
|
- deadsnakes
|
||||||
|
- ubuntu-toolchain-r-test
|
||||||
|
packages:
|
||||||
|
- g++-7
|
||||||
|
- python3.8-dev
|
||||||
|
- python3.8-venv
|
||||||
|
# Currently there is no numpy/scipy wheels available for python3.8
|
||||||
|
# TODO: remove next before_install, install and script clause when the wheels become available
|
||||||
|
before_install:
|
||||||
|
- pyenv global $(pyenv whence 2to3) # activate all python versions
|
||||||
|
- PY_CMD=python3
|
||||||
|
- $PY_CMD -m pip install --user --upgrade pip wheel setuptools
|
||||||
|
install:
|
||||||
|
- $PY_CMD -m pip install --user --upgrade pytest
|
||||||
|
script:
|
||||||
|
- |
|
||||||
|
# Barebones build
|
||||||
|
cmake -DCMAKE_BUILD_TYPE=Debug -DPYBIND11_WERROR=ON -DDOWNLOAD_CATCH=ON -DPYTHON_EXECUTABLE=$(which $PY_CMD) .
|
||||||
|
make pytest -j 2 && make cpptest -j 2
|
||||||
|
- os: osx
|
||||||
|
name: Python 2.7, c++14, AppleClang 7.3, CMake test
|
||||||
|
osx_image: xcode7.3
|
||||||
|
env: PYTHON=2.7 CPP=14 CLANG CMAKE=1
|
||||||
|
- os: osx
|
||||||
|
name: Python 3.7, c++14, AppleClang 9, Debug build
|
||||||
|
osx_image: xcode9.4
|
||||||
|
env: PYTHON=3.7 CPP=14 CLANG DEBUG=1
|
||||||
|
# Test a PyPy 2.7 build
|
||||||
|
- os: linux
|
||||||
|
dist: trusty
|
||||||
|
env: PYPY=5.8 PYTHON=2.7 CPP=11 GCC=4.8
|
||||||
|
name: PyPy 5.8, Python 2.7, c++11, gcc 4.8
|
||||||
|
addons:
|
||||||
|
apt:
|
||||||
|
packages:
|
||||||
|
- libblas-dev
|
||||||
|
- liblapack-dev
|
||||||
|
- gfortran
|
||||||
|
# Build in 32-bit mode and tests against the CMake-installed version
|
||||||
|
- os: linux
|
||||||
|
dist: trusty
|
||||||
|
services: docker
|
||||||
|
env: DOCKER=i386/debian:stretch PYTHON=3.5 CPP=14 GCC=6 INSTALL=1
|
||||||
|
name: Python 3.5, c++14, gcc 6, 32-bit
|
||||||
|
script:
|
||||||
|
- |
|
||||||
|
# Consolidated 32-bit Docker Build + Install
|
||||||
|
set -ex
|
||||||
|
$SCRIPT_RUN_PREFIX sh -c "
|
||||||
|
set -ex
|
||||||
|
cmake ${CMAKE_EXTRA_ARGS} -DPYBIND11_INSTALL=1 -DPYBIND11_TEST=0 .
|
||||||
|
make install
|
||||||
|
cp -a tests /pybind11-tests
|
||||||
|
mkdir /build-tests && cd /build-tests
|
||||||
|
cmake ../pybind11-tests ${CMAKE_EXTRA_ARGS} -DPYBIND11_WERROR=ON
|
||||||
|
make pytest -j 2"
|
||||||
|
set +ex
|
||||||
|
cache:
|
||||||
|
directories:
|
||||||
|
- $HOME/.local/bin
|
||||||
|
- $HOME/.local/lib
|
||||||
|
- $HOME/.local/include
|
||||||
|
- $HOME/Library/Python
|
||||||
|
before_install:
|
||||||
|
- |
|
||||||
|
# Configure build variables
|
||||||
|
set -ex
|
||||||
|
if [ "$TRAVIS_OS_NAME" = "linux" ]; then
|
||||||
|
if [ -n "$CLANG" ]; then
|
||||||
|
export CXX=clang++-$CLANG CC=clang-$CLANG
|
||||||
|
EXTRA_PACKAGES+=" clang-$CLANG llvm-$CLANG-dev"
|
||||||
|
else
|
||||||
|
if [ -z "$GCC" ]; then GCC=4.8
|
||||||
|
else EXTRA_PACKAGES+=" g++-$GCC"
|
||||||
|
fi
|
||||||
|
export CXX=g++-$GCC CC=gcc-$GCC
|
||||||
|
fi
|
||||||
|
elif [ "$TRAVIS_OS_NAME" = "osx" ]; then
|
||||||
|
export CXX=clang++ CC=clang;
|
||||||
|
fi
|
||||||
|
if [ -n "$CPP" ]; then CPP=-std=c++$CPP; fi
|
||||||
|
if [ "${PYTHON:0:1}" = "3" ]; then PY=3; fi
|
||||||
|
if [ -n "$DEBUG" ]; then CMAKE_EXTRA_ARGS+=" -DCMAKE_BUILD_TYPE=Debug"; fi
|
||||||
|
set +ex
|
||||||
|
- |
|
||||||
|
# Initialize environment
|
||||||
|
set -ex
|
||||||
|
if [ -n "$DOCKER" ]; then
|
||||||
|
docker pull $DOCKER
|
||||||
|
|
||||||
|
containerid=$(docker run --detach --tty \
|
||||||
|
--volume="$PWD":/pybind11 --workdir=/pybind11 \
|
||||||
|
--env="CC=$CC" --env="CXX=$CXX" --env="DEBIAN_FRONTEND=$DEBIAN_FRONTEND" \
|
||||||
|
--env=GCC_COLORS=\ \
|
||||||
|
$DOCKER)
|
||||||
|
SCRIPT_RUN_PREFIX="docker exec --tty $containerid"
|
||||||
|
$SCRIPT_RUN_PREFIX sh -c 'for s in 0 15; do sleep $s; apt-get update && apt-get -qy dist-upgrade && break; done'
|
||||||
|
else
|
||||||
|
if [ "$PYPY" = "5.8" ]; then
|
||||||
|
curl -fSL https://bitbucket.org/pypy/pypy/downloads/pypy2-v5.8.0-linux64.tar.bz2 | tar xj
|
||||||
|
PY_CMD=$(echo `pwd`/pypy2-v5.8.0-linux64/bin/pypy)
|
||||||
|
CMAKE_EXTRA_ARGS+=" -DPYTHON_EXECUTABLE:FILEPATH=$PY_CMD"
|
||||||
|
else
|
||||||
|
PY_CMD=python$PYTHON
|
||||||
|
if [ "$TRAVIS_OS_NAME" = "osx" ]; then
|
||||||
|
if [ "$PY" = "3" ]; then
|
||||||
|
brew update && brew unlink python@2 && brew upgrade python
|
||||||
|
else
|
||||||
|
curl -fsSL https://bootstrap.pypa.io/get-pip.py | $PY_CMD - --user
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
if [ "$PY" = 3 ] || [ -n "$PYPY" ]; then
|
||||||
|
$PY_CMD -m ensurepip --user
|
||||||
|
fi
|
||||||
|
$PY_CMD --version
|
||||||
|
$PY_CMD -m pip install --user --upgrade pip wheel
|
||||||
|
fi
|
||||||
|
set +ex
|
||||||
|
install:
|
||||||
|
- |
|
||||||
|
# Install dependencies
|
||||||
|
set -ex
|
||||||
|
cmake --version
|
||||||
|
if [ -n "$DOCKER" ]; then
|
||||||
|
if [ -n "$DEBUG" ]; then
|
||||||
|
PY_DEBUG="python$PYTHON-dbg python$PY-scipy-dbg"
|
||||||
|
CMAKE_EXTRA_ARGS+=" -DPYTHON_EXECUTABLE=/usr/bin/python${PYTHON}dm"
|
||||||
|
fi
|
||||||
|
$SCRIPT_RUN_PREFIX sh -c "for s in 0 15; do sleep \$s; \
|
||||||
|
apt-get -qy --no-install-recommends install \
|
||||||
|
$PY_DEBUG python$PYTHON-dev python$PY-pytest python$PY-scipy \
|
||||||
|
libeigen3-dev libboost-dev cmake make ${EXTRA_PACKAGES} && break; done"
|
||||||
|
else
|
||||||
|
|
||||||
|
if [ "$CLANG" = "7" ]; then
|
||||||
|
export CXXFLAGS="-stdlib=libc++"
|
||||||
|
fi
|
||||||
|
|
||||||
|
export NPY_NUM_BUILD_JOBS=2
|
||||||
|
echo "Installing pytest, numpy, scipy..."
|
||||||
|
local PIP_CMD=""
|
||||||
|
if [ -n $PYPY ]; then
|
||||||
|
# For expediency, install only versions that are available on the extra index.
|
||||||
|
travis_wait 30 \
|
||||||
|
$PY_CMD -m pip install --user --upgrade --extra-index-url https://imaginary.ca/trusty-pypi \
|
||||||
|
pytest numpy==1.15.4 scipy==1.2.0
|
||||||
|
else
|
||||||
|
$PY_CMD -m pip install --user --upgrade pytest numpy scipy
|
||||||
|
fi
|
||||||
|
echo "done."
|
||||||
|
|
||||||
|
mkdir eigen
|
||||||
|
curl -fsSL https://bitbucket.org/eigen/eigen/get/3.3.4.tar.bz2 | \
|
||||||
|
tar --extract -j --directory=eigen --strip-components=1
|
||||||
|
export CMAKE_INCLUDE_PATH="${CMAKE_INCLUDE_PATH:+$CMAKE_INCLUDE_PATH:}$PWD/eigen"
|
||||||
|
fi
|
||||||
|
set +ex
|
||||||
|
script:
|
||||||
|
- |
|
||||||
|
# CMake Configuration
|
||||||
|
set -ex
|
||||||
|
$SCRIPT_RUN_PREFIX cmake ${CMAKE_EXTRA_ARGS} \
|
||||||
|
-DPYBIND11_PYTHON_VERSION=$PYTHON \
|
||||||
|
-DPYBIND11_CPP_STANDARD=$CPP \
|
||||||
|
-DPYBIND11_WERROR=${WERROR:-ON} \
|
||||||
|
-DDOWNLOAD_CATCH=${DOWNLOAD_CATCH:-ON} \
|
||||||
|
.
|
||||||
|
set +ex
|
||||||
|
- |
|
||||||
|
# pytest
|
||||||
|
set -ex
|
||||||
|
$SCRIPT_RUN_PREFIX make pytest -j 2 VERBOSE=1
|
||||||
|
set +ex
|
||||||
|
- |
|
||||||
|
# cpptest
|
||||||
|
set -ex
|
||||||
|
$SCRIPT_RUN_PREFIX make cpptest -j 2
|
||||||
|
set +ex
|
||||||
|
- |
|
||||||
|
# CMake Build Interface
|
||||||
|
set -ex
|
||||||
|
if [ -n "$CMAKE" ]; then $SCRIPT_RUN_PREFIX make test_cmake_build; fi
|
||||||
|
set +ex
|
||||||
|
after_failure: cat tests/test_cmake_build/*.log*
|
||||||
|
after_script:
|
||||||
|
- |
|
||||||
|
# Cleanup (Docker)
|
||||||
|
set -ex
|
||||||
|
if [ -n "$DOCKER" ]; then docker stop "$containerid"; docker rm "$containerid"; fi
|
||||||
|
set +ex
|
157
3rdparty/pybind11/CMakeLists.txt
vendored
Normal file
157
3rdparty/pybind11/CMakeLists.txt
vendored
Normal file
@ -0,0 +1,157 @@
|
|||||||
|
# CMakeLists.txt -- Build system for the pybind11 modules
|
||||||
|
#
|
||||||
|
# Copyright (c) 2015 Wenzel Jakob <wenzel@inf.ethz.ch>
|
||||||
|
#
|
||||||
|
# All rights reserved. Use of this source code is governed by a
|
||||||
|
# BSD-style license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
cmake_minimum_required(VERSION 2.8.12)
|
||||||
|
|
||||||
|
if (POLICY CMP0048)
|
||||||
|
# cmake warns if loaded from a min-3.0-required parent dir, so silence the warning:
|
||||||
|
cmake_policy(SET CMP0048 NEW)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# CMake versions < 3.4.0 do not support try_compile/pthread checks without C as active language.
|
||||||
|
if(CMAKE_VERSION VERSION_LESS 3.4.0)
|
||||||
|
project(pybind11)
|
||||||
|
else()
|
||||||
|
project(pybind11 CXX)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Check if pybind11 is being used directly or via add_subdirectory
|
||||||
|
set(PYBIND11_MASTER_PROJECT OFF)
|
||||||
|
if (CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_SOURCE_DIR)
|
||||||
|
set(PYBIND11_MASTER_PROJECT ON)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
option(PYBIND11_INSTALL "Install pybind11 header files?" ${PYBIND11_MASTER_PROJECT})
|
||||||
|
option(PYBIND11_TEST "Build pybind11 test suite?" ${PYBIND11_MASTER_PROJECT})
|
||||||
|
|
||||||
|
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/tools")
|
||||||
|
|
||||||
|
include(pybind11Tools)
|
||||||
|
|
||||||
|
# Cache variables so pybind11_add_module can be used in parent projects
|
||||||
|
set(PYBIND11_INCLUDE_DIR "${CMAKE_CURRENT_LIST_DIR}/include" CACHE INTERNAL "")
|
||||||
|
set(PYTHON_INCLUDE_DIRS ${PYTHON_INCLUDE_DIRS} CACHE INTERNAL "")
|
||||||
|
set(PYTHON_LIBRARIES ${PYTHON_LIBRARIES} CACHE INTERNAL "")
|
||||||
|
set(PYTHON_MODULE_PREFIX ${PYTHON_MODULE_PREFIX} CACHE INTERNAL "")
|
||||||
|
set(PYTHON_MODULE_EXTENSION ${PYTHON_MODULE_EXTENSION} CACHE INTERNAL "")
|
||||||
|
set(PYTHON_VERSION_MAJOR ${PYTHON_VERSION_MAJOR} CACHE INTERNAL "")
|
||||||
|
set(PYTHON_VERSION_MINOR ${PYTHON_VERSION_MINOR} CACHE INTERNAL "")
|
||||||
|
|
||||||
|
# NB: when adding a header don't forget to also add it to setup.py
|
||||||
|
set(PYBIND11_HEADERS
|
||||||
|
include/pybind11/detail/class.h
|
||||||
|
include/pybind11/detail/common.h
|
||||||
|
include/pybind11/detail/descr.h
|
||||||
|
include/pybind11/detail/init.h
|
||||||
|
include/pybind11/detail/internals.h
|
||||||
|
include/pybind11/detail/typeid.h
|
||||||
|
include/pybind11/attr.h
|
||||||
|
include/pybind11/buffer_info.h
|
||||||
|
include/pybind11/cast.h
|
||||||
|
include/pybind11/chrono.h
|
||||||
|
include/pybind11/common.h
|
||||||
|
include/pybind11/complex.h
|
||||||
|
include/pybind11/options.h
|
||||||
|
include/pybind11/eigen.h
|
||||||
|
include/pybind11/embed.h
|
||||||
|
include/pybind11/eval.h
|
||||||
|
include/pybind11/functional.h
|
||||||
|
include/pybind11/numpy.h
|
||||||
|
include/pybind11/operators.h
|
||||||
|
include/pybind11/pybind11.h
|
||||||
|
include/pybind11/pytypes.h
|
||||||
|
include/pybind11/stl.h
|
||||||
|
include/pybind11/stl_bind.h
|
||||||
|
)
|
||||||
|
string(REPLACE "include/" "${CMAKE_CURRENT_SOURCE_DIR}/include/"
|
||||||
|
PYBIND11_HEADERS "${PYBIND11_HEADERS}")
|
||||||
|
|
||||||
|
if (PYBIND11_TEST)
|
||||||
|
add_subdirectory(tests)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
include(GNUInstallDirs)
|
||||||
|
include(CMakePackageConfigHelpers)
|
||||||
|
|
||||||
|
# extract project version from source
|
||||||
|
file(STRINGS "${PYBIND11_INCLUDE_DIR}/pybind11/detail/common.h" pybind11_version_defines
|
||||||
|
REGEX "#define PYBIND11_VERSION_(MAJOR|MINOR|PATCH) ")
|
||||||
|
foreach(ver ${pybind11_version_defines})
|
||||||
|
if (ver MATCHES "#define PYBIND11_VERSION_(MAJOR|MINOR|PATCH) +([^ ]+)$")
|
||||||
|
set(PYBIND11_VERSION_${CMAKE_MATCH_1} "${CMAKE_MATCH_2}" CACHE INTERNAL "")
|
||||||
|
endif()
|
||||||
|
endforeach()
|
||||||
|
set(${PROJECT_NAME}_VERSION ${PYBIND11_VERSION_MAJOR}.${PYBIND11_VERSION_MINOR}.${PYBIND11_VERSION_PATCH})
|
||||||
|
message(STATUS "pybind11 v${${PROJECT_NAME}_VERSION}")
|
||||||
|
|
||||||
|
option (USE_PYTHON_INCLUDE_DIR "Install pybind11 headers in Python include directory instead of default installation prefix" OFF)
|
||||||
|
if (USE_PYTHON_INCLUDE_DIR)
|
||||||
|
file(RELATIVE_PATH CMAKE_INSTALL_INCLUDEDIR ${CMAKE_INSTALL_PREFIX} ${PYTHON_INCLUDE_DIRS})
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(NOT (CMAKE_VERSION VERSION_LESS 3.0)) # CMake >= 3.0
|
||||||
|
# Build an interface library target:
|
||||||
|
add_library(pybind11 INTERFACE)
|
||||||
|
add_library(pybind11::pybind11 ALIAS pybind11) # to match exported target
|
||||||
|
target_include_directories(pybind11 INTERFACE $<BUILD_INTERFACE:${PYBIND11_INCLUDE_DIR}>
|
||||||
|
$<BUILD_INTERFACE:${PYTHON_INCLUDE_DIRS}>
|
||||||
|
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>)
|
||||||
|
target_compile_options(pybind11 INTERFACE $<BUILD_INTERFACE:${PYBIND11_CPP_STANDARD}>)
|
||||||
|
|
||||||
|
add_library(module INTERFACE)
|
||||||
|
add_library(pybind11::module ALIAS module)
|
||||||
|
if(NOT MSVC)
|
||||||
|
target_compile_options(module INTERFACE -fvisibility=hidden)
|
||||||
|
endif()
|
||||||
|
target_link_libraries(module INTERFACE pybind11::pybind11)
|
||||||
|
if(WIN32 OR CYGWIN)
|
||||||
|
target_link_libraries(module INTERFACE $<BUILD_INTERFACE:${PYTHON_LIBRARIES}>)
|
||||||
|
elseif(APPLE)
|
||||||
|
target_link_libraries(module INTERFACE "-undefined dynamic_lookup")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
add_library(embed INTERFACE)
|
||||||
|
add_library(pybind11::embed ALIAS embed)
|
||||||
|
target_link_libraries(embed INTERFACE pybind11::pybind11 $<BUILD_INTERFACE:${PYTHON_LIBRARIES}>)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if (PYBIND11_INSTALL)
|
||||||
|
install(DIRECTORY ${PYBIND11_INCLUDE_DIR}/pybind11 DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
|
||||||
|
# GNUInstallDirs "DATADIR" wrong here; CMake search path wants "share".
|
||||||
|
set(PYBIND11_CMAKECONFIG_INSTALL_DIR "share/cmake/${PROJECT_NAME}" CACHE STRING "install path for pybind11Config.cmake")
|
||||||
|
|
||||||
|
configure_package_config_file(tools/${PROJECT_NAME}Config.cmake.in
|
||||||
|
"${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Config.cmake"
|
||||||
|
INSTALL_DESTINATION ${PYBIND11_CMAKECONFIG_INSTALL_DIR})
|
||||||
|
# Remove CMAKE_SIZEOF_VOID_P from ConfigVersion.cmake since the library does
|
||||||
|
# not depend on architecture specific settings or libraries.
|
||||||
|
set(_PYBIND11_CMAKE_SIZEOF_VOID_P ${CMAKE_SIZEOF_VOID_P})
|
||||||
|
unset(CMAKE_SIZEOF_VOID_P)
|
||||||
|
write_basic_package_version_file(${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake
|
||||||
|
VERSION ${${PROJECT_NAME}_VERSION}
|
||||||
|
COMPATIBILITY AnyNewerVersion)
|
||||||
|
set(CMAKE_SIZEOF_VOID_P ${_PYBIND11_CMAKE_SIZEOF_VOID_P})
|
||||||
|
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Config.cmake
|
||||||
|
${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake
|
||||||
|
tools/FindPythonLibsNew.cmake
|
||||||
|
tools/pybind11Tools.cmake
|
||||||
|
DESTINATION ${PYBIND11_CMAKECONFIG_INSTALL_DIR})
|
||||||
|
|
||||||
|
if(NOT (CMAKE_VERSION VERSION_LESS 3.0))
|
||||||
|
if(NOT PYBIND11_EXPORT_NAME)
|
||||||
|
set(PYBIND11_EXPORT_NAME "${PROJECT_NAME}Targets")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
install(TARGETS pybind11 module embed
|
||||||
|
EXPORT "${PYBIND11_EXPORT_NAME}")
|
||||||
|
if(PYBIND11_MASTER_PROJECT)
|
||||||
|
install(EXPORT "${PYBIND11_EXPORT_NAME}"
|
||||||
|
NAMESPACE "${PROJECT_NAME}::"
|
||||||
|
DESTINATION ${PYBIND11_CMAKECONFIG_INSTALL_DIR})
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
endif()
|
49
3rdparty/pybind11/CONTRIBUTING.md
vendored
Normal file
49
3rdparty/pybind11/CONTRIBUTING.md
vendored
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
Thank you for your interest in this project! Please refer to the following
|
||||||
|
sections on how to contribute code and bug reports.
|
||||||
|
|
||||||
|
### Reporting bugs
|
||||||
|
|
||||||
|
At the moment, this project is run in the spare time of a single person
|
||||||
|
([Wenzel Jakob](http://rgl.epfl.ch/people/wjakob)) with very limited resources
|
||||||
|
for issue tracker tickets. Thus, before submitting a question or bug report,
|
||||||
|
please take a moment of your time and ensure that your issue isn't already
|
||||||
|
discussed in the project documentation provided at
|
||||||
|
[http://pybind11.readthedocs.org/en/latest](http://pybind11.readthedocs.org/en/latest).
|
||||||
|
|
||||||
|
Assuming that you have identified a previously unknown problem or an important
|
||||||
|
question, it's essential that you submit a self-contained and minimal piece of
|
||||||
|
code that reproduces the problem. In other words: no external dependencies,
|
||||||
|
isolate the function(s) that cause breakage, submit matched and complete C++
|
||||||
|
and Python snippets that can be easily compiled and run on my end.
|
||||||
|
|
||||||
|
## Pull requests
|
||||||
|
Contributions are submitted, reviewed, and accepted using Github pull requests.
|
||||||
|
Please refer to [this
|
||||||
|
article](https://help.github.com/articles/using-pull-requests) for details and
|
||||||
|
adhere to the following rules to make the process as smooth as possible:
|
||||||
|
|
||||||
|
* Make a new branch for every feature you're working on.
|
||||||
|
* Make small and clean pull requests that are easy to review but make sure they
|
||||||
|
do add value by themselves.
|
||||||
|
* Add tests for any new functionality and run the test suite (``make pytest``)
|
||||||
|
to ensure that no existing features break.
|
||||||
|
* Please run ``flake8`` and ``tools/check-style.sh`` to check your code matches
|
||||||
|
the project style. (Note that ``check-style.sh`` requires ``gawk``.)
|
||||||
|
* This project has a strong focus on providing general solutions using a
|
||||||
|
minimal amount of code, thus small pull requests are greatly preferred.
|
||||||
|
|
||||||
|
### Licensing of contributions
|
||||||
|
|
||||||
|
pybind11 is provided under a BSD-style license that can be found in the
|
||||||
|
``LICENSE`` file. By using, distributing, or contributing to this project, you
|
||||||
|
agree to the terms and conditions of this license.
|
||||||
|
|
||||||
|
You are under no obligation whatsoever to provide any bug fixes, patches, or
|
||||||
|
upgrades to the features, functionality or performance of the source code
|
||||||
|
("Enhancements") to anyone; however, if you choose to make your Enhancements
|
||||||
|
available either publicly, or directly to the author of this software, without
|
||||||
|
imposing a separate written license agreement for such Enhancements, then you
|
||||||
|
hereby grant the following license: a non-exclusive, royalty-free perpetual
|
||||||
|
license to install, use, modify, prepare derivative works, incorporate into
|
||||||
|
other computer software, distribute, and sublicense such enhancements or
|
||||||
|
derivative works thereof, in binary and source code form.
|
17
3rdparty/pybind11/ISSUE_TEMPLATE.md
vendored
Normal file
17
3rdparty/pybind11/ISSUE_TEMPLATE.md
vendored
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
Make sure you've completed the following steps before submitting your issue -- thank you!
|
||||||
|
|
||||||
|
1. Check if your question has already been answered in the [FAQ](http://pybind11.readthedocs.io/en/latest/faq.html) section.
|
||||||
|
2. Make sure you've read the [documentation](http://pybind11.readthedocs.io/en/latest/). Your issue may be addressed there.
|
||||||
|
3. If those resources didn't help and you only have a short question (not a bug report), consider asking in the [Gitter chat room](https://gitter.im/pybind/Lobby).
|
||||||
|
4. If you have a genuine bug report or a more complex question which is not answered in the previous items (or not suitable for chat), please fill in the details below.
|
||||||
|
5. Include a self-contained and minimal piece of code that reproduces the problem. If that's not possible, try to make the description as clear as possible.
|
||||||
|
|
||||||
|
*After reading, remove this checklist and the template text in parentheses below.*
|
||||||
|
|
||||||
|
## Issue description
|
||||||
|
|
||||||
|
(Provide a short description, state the expected behavior and what actually happens.)
|
||||||
|
|
||||||
|
## Reproducible example code
|
||||||
|
|
||||||
|
(The code should be minimal, have no external dependencies, isolate the function(s) that cause breakage. Submit matched and complete C++ and Python snippets that can be easily compiled and run to diagnose the issue.)
|
29
3rdparty/pybind11/LICENSE
vendored
Normal file
29
3rdparty/pybind11/LICENSE
vendored
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch>, All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions are met:
|
||||||
|
|
||||||
|
1. Redistributions of source code must retain the above copyright notice, this
|
||||||
|
list of conditions and the following disclaimer.
|
||||||
|
|
||||||
|
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
this list of conditions and the following disclaimer in the documentation
|
||||||
|
and/or other materials provided with the distribution.
|
||||||
|
|
||||||
|
3. Neither the name of the copyright holder nor the names of its contributors
|
||||||
|
may be used to endorse or promote products derived from this software
|
||||||
|
without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||||
|
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||||
|
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||||
|
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||||
|
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||||
|
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
|
Please also refer to the file CONTRIBUTING.md, which clarifies licensing of
|
||||||
|
external contributions to this project including patches, pull requests, etc.
|
2
3rdparty/pybind11/MANIFEST.in
vendored
Normal file
2
3rdparty/pybind11/MANIFEST.in
vendored
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
recursive-include include/pybind11 *.h
|
||||||
|
include LICENSE README.md CONTRIBUTING.md
|
129
3rdparty/pybind11/README.md
vendored
Normal file
129
3rdparty/pybind11/README.md
vendored
Normal file
@ -0,0 +1,129 @@
|
|||||||
|

|
||||||
|
|
||||||
|
# pybind11 — Seamless operability between C++11 and Python
|
||||||
|
|
||||||
|
[](http://pybind11.readthedocs.org/en/master/?badge=master)
|
||||||
|
[](http://pybind11.readthedocs.org/en/stable/?badge=stable)
|
||||||
|
[](https://gitter.im/pybind/Lobby)
|
||||||
|
[](https://travis-ci.org/pybind/pybind11)
|
||||||
|
[](https://ci.appveyor.com/project/wjakob/pybind11)
|
||||||
|
|
||||||
|
**pybind11** is a lightweight header-only library that exposes C++ types in Python
|
||||||
|
and vice versa, mainly to create Python bindings of existing C++ code. Its
|
||||||
|
goals and syntax are similar to the excellent
|
||||||
|
[Boost.Python](http://www.boost.org/doc/libs/1_58_0/libs/python/doc/) library
|
||||||
|
by David Abrahams: to minimize boilerplate code in traditional extension
|
||||||
|
modules by inferring type information using compile-time introspection.
|
||||||
|
|
||||||
|
The main issue with Boost.Python—and the reason for creating such a similar
|
||||||
|
project—is Boost. Boost is an enormously large and complex suite of utility
|
||||||
|
libraries that works with almost every C++ compiler in existence. This
|
||||||
|
compatibility has its cost: arcane template tricks and workarounds are
|
||||||
|
necessary to support the oldest and buggiest of compiler specimens. Now that
|
||||||
|
C++11-compatible compilers are widely available, this heavy machinery has
|
||||||
|
become an excessively large and unnecessary dependency.
|
||||||
|
|
||||||
|
Think of this library as a tiny self-contained version of Boost.Python with
|
||||||
|
everything stripped away that isn't relevant for binding generation. Without
|
||||||
|
comments, the core header files only require ~4K lines of code and depend on
|
||||||
|
Python (2.7 or 3.x, or PyPy2.7 >= 5.7) and the C++ standard library. This
|
||||||
|
compact implementation was possible thanks to some of the new C++11 language
|
||||||
|
features (specifically: tuples, lambda functions and variadic templates). Since
|
||||||
|
its creation, this library has grown beyond Boost.Python in many ways, leading
|
||||||
|
to dramatically simpler binding code in many common situations.
|
||||||
|
|
||||||
|
Tutorial and reference documentation is provided at
|
||||||
|
[http://pybind11.readthedocs.org/en/master](http://pybind11.readthedocs.org/en/master).
|
||||||
|
A PDF version of the manual is available
|
||||||
|
[here](https://media.readthedocs.org/pdf/pybind11/master/pybind11.pdf).
|
||||||
|
|
||||||
|
## Core features
|
||||||
|
pybind11 can map the following core C++ features to Python
|
||||||
|
|
||||||
|
- Functions accepting and returning custom data structures per value, reference, or pointer
|
||||||
|
- Instance methods and static methods
|
||||||
|
- Overloaded functions
|
||||||
|
- Instance attributes and static attributes
|
||||||
|
- Arbitrary exception types
|
||||||
|
- Enumerations
|
||||||
|
- Callbacks
|
||||||
|
- Iterators and ranges
|
||||||
|
- Custom operators
|
||||||
|
- Single and multiple inheritance
|
||||||
|
- STL data structures
|
||||||
|
- Smart pointers with reference counting like ``std::shared_ptr``
|
||||||
|
- Internal references with correct reference counting
|
||||||
|
- C++ classes with virtual (and pure virtual) methods can be extended in Python
|
||||||
|
|
||||||
|
## Goodies
|
||||||
|
In addition to the core functionality, pybind11 provides some extra goodies:
|
||||||
|
|
||||||
|
- Python 2.7, 3.x, and PyPy (PyPy2.7 >= 5.7) are supported with an
|
||||||
|
implementation-agnostic interface.
|
||||||
|
|
||||||
|
- It is possible to bind C++11 lambda functions with captured variables. The
|
||||||
|
lambda capture data is stored inside the resulting Python function object.
|
||||||
|
|
||||||
|
- pybind11 uses C++11 move constructors and move assignment operators whenever
|
||||||
|
possible to efficiently transfer custom data types.
|
||||||
|
|
||||||
|
- It's easy to expose the internal storage of custom data types through
|
||||||
|
Pythons' buffer protocols. This is handy e.g. for fast conversion between
|
||||||
|
C++ matrix classes like Eigen and NumPy without expensive copy operations.
|
||||||
|
|
||||||
|
- pybind11 can automatically vectorize functions so that they are transparently
|
||||||
|
applied to all entries of one or more NumPy array arguments.
|
||||||
|
|
||||||
|
- Python's slice-based access and assignment operations can be supported with
|
||||||
|
just a few lines of code.
|
||||||
|
|
||||||
|
- Everything is contained in just a few header files; there is no need to link
|
||||||
|
against any additional libraries.
|
||||||
|
|
||||||
|
- Binaries are generally smaller by a factor of at least 2 compared to
|
||||||
|
equivalent bindings generated by Boost.Python. A recent pybind11 conversion
|
||||||
|
of PyRosetta, an enormous Boost.Python binding project,
|
||||||
|
[reported](http://graylab.jhu.edu/RosettaCon2016/PyRosetta-4.pdf) a binary
|
||||||
|
size reduction of **5.4x** and compile time reduction by **5.8x**.
|
||||||
|
|
||||||
|
- Function signatures are precomputed at compile time (using ``constexpr``),
|
||||||
|
leading to smaller binaries.
|
||||||
|
|
||||||
|
- With little extra effort, C++ types can be pickled and unpickled similar to
|
||||||
|
regular Python objects.
|
||||||
|
|
||||||
|
## Supported compilers
|
||||||
|
|
||||||
|
1. Clang/LLVM 3.3 or newer (for Apple Xcode's clang, this is 5.0.0 or newer)
|
||||||
|
2. GCC 4.8 or newer
|
||||||
|
3. Microsoft Visual Studio 2015 Update 3 or newer
|
||||||
|
4. Intel C++ compiler 17 or newer (16 with pybind11 v2.0 and 15 with pybind11 v2.0 and a [workaround](https://github.com/pybind/pybind11/issues/276))
|
||||||
|
5. Cygwin/GCC (tested on 2.5.1)
|
||||||
|
|
||||||
|
## About
|
||||||
|
|
||||||
|
This project was created by [Wenzel Jakob](http://rgl.epfl.ch/people/wjakob).
|
||||||
|
Significant features and/or improvements to the code were contributed by
|
||||||
|
Jonas Adler,
|
||||||
|
Lori A. Burns,
|
||||||
|
Sylvain Corlay,
|
||||||
|
Trent Houliston,
|
||||||
|
Axel Huebl,
|
||||||
|
@hulucc,
|
||||||
|
Sergey Lyskov
|
||||||
|
Johan Mabille,
|
||||||
|
Tomasz Miąsko,
|
||||||
|
Dean Moldovan,
|
||||||
|
Ben Pritchard,
|
||||||
|
Jason Rhinelander,
|
||||||
|
Boris Schäling,
|
||||||
|
Pim Schellart,
|
||||||
|
Henry Schreiner,
|
||||||
|
Ivan Smirnov, and
|
||||||
|
Patrick Stewart.
|
||||||
|
|
||||||
|
### License
|
||||||
|
|
||||||
|
pybind11 is provided under a BSD-style license that can be found in the
|
||||||
|
``LICENSE`` file. By using, distributing, or contributing to this project,
|
||||||
|
you agree to the terms and conditions of this license.
|
20
3rdparty/pybind11/docs/Doxyfile
vendored
Normal file
20
3rdparty/pybind11/docs/Doxyfile
vendored
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
PROJECT_NAME = pybind11
|
||||||
|
INPUT = ../include/pybind11/
|
||||||
|
RECURSIVE = YES
|
||||||
|
|
||||||
|
GENERATE_HTML = NO
|
||||||
|
GENERATE_LATEX = NO
|
||||||
|
GENERATE_XML = YES
|
||||||
|
XML_OUTPUT = .build/doxygenxml
|
||||||
|
XML_PROGRAMLISTING = YES
|
||||||
|
|
||||||
|
MACRO_EXPANSION = YES
|
||||||
|
EXPAND_ONLY_PREDEF = YES
|
||||||
|
EXPAND_AS_DEFINED = PYBIND11_RUNTIME_EXCEPTION
|
||||||
|
|
||||||
|
ALIASES = "rst=\verbatim embed:rst"
|
||||||
|
ALIASES += "endrst=\endverbatim"
|
||||||
|
|
||||||
|
QUIET = YES
|
||||||
|
WARNINGS = YES
|
||||||
|
WARN_IF_UNDOCUMENTED = NO
|
11
3rdparty/pybind11/docs/_static/theme_overrides.css
vendored
Normal file
11
3rdparty/pybind11/docs/_static/theme_overrides.css
vendored
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
.wy-table-responsive table td,
|
||||||
|
.wy-table-responsive table th {
|
||||||
|
white-space: initial !important;
|
||||||
|
}
|
||||||
|
.rst-content table.docutils td {
|
||||||
|
vertical-align: top !important;
|
||||||
|
}
|
||||||
|
div[class^='highlight'] pre {
|
||||||
|
white-space: pre;
|
||||||
|
white-space: pre-wrap;
|
||||||
|
}
|
81
3rdparty/pybind11/docs/advanced/cast/chrono.rst
vendored
Normal file
81
3rdparty/pybind11/docs/advanced/cast/chrono.rst
vendored
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
Chrono
|
||||||
|
======
|
||||||
|
|
||||||
|
When including the additional header file :file:`pybind11/chrono.h` conversions
|
||||||
|
from C++11 chrono datatypes to python datetime objects are automatically enabled.
|
||||||
|
This header also enables conversions of python floats (often from sources such
|
||||||
|
as ``time.monotonic()``, ``time.perf_counter()`` and ``time.process_time()``)
|
||||||
|
into durations.
|
||||||
|
|
||||||
|
An overview of clocks in C++11
|
||||||
|
------------------------------
|
||||||
|
|
||||||
|
A point of confusion when using these conversions is the differences between
|
||||||
|
clocks provided in C++11. There are three clock types defined by the C++11
|
||||||
|
standard and users can define their own if needed. Each of these clocks have
|
||||||
|
different properties and when converting to and from python will give different
|
||||||
|
results.
|
||||||
|
|
||||||
|
The first clock defined by the standard is ``std::chrono::system_clock``. This
|
||||||
|
clock measures the current date and time. However, this clock changes with to
|
||||||
|
updates to the operating system time. For example, if your time is synchronised
|
||||||
|
with a time server this clock will change. This makes this clock a poor choice
|
||||||
|
for timing purposes but good for measuring the wall time.
|
||||||
|
|
||||||
|
The second clock defined in the standard is ``std::chrono::steady_clock``.
|
||||||
|
This clock ticks at a steady rate and is never adjusted. This makes it excellent
|
||||||
|
for timing purposes, however the value in this clock does not correspond to the
|
||||||
|
current date and time. Often this clock will be the amount of time your system
|
||||||
|
has been on, although it does not have to be. This clock will never be the same
|
||||||
|
clock as the system clock as the system clock can change but steady clocks
|
||||||
|
cannot.
|
||||||
|
|
||||||
|
The third clock defined in the standard is ``std::chrono::high_resolution_clock``.
|
||||||
|
This clock is the clock that has the highest resolution out of the clocks in the
|
||||||
|
system. It is normally a typedef to either the system clock or the steady clock
|
||||||
|
but can be its own independent clock. This is important as when using these
|
||||||
|
conversions as the types you get in python for this clock might be different
|
||||||
|
depending on the system.
|
||||||
|
If it is a typedef of the system clock, python will get datetime objects, but if
|
||||||
|
it is a different clock they will be timedelta objects.
|
||||||
|
|
||||||
|
Provided conversions
|
||||||
|
--------------------
|
||||||
|
|
||||||
|
.. rubric:: C++ to Python
|
||||||
|
|
||||||
|
- ``std::chrono::system_clock::time_point`` → ``datetime.datetime``
|
||||||
|
System clock times are converted to python datetime instances. They are
|
||||||
|
in the local timezone, but do not have any timezone information attached
|
||||||
|
to them (they are naive datetime objects).
|
||||||
|
|
||||||
|
- ``std::chrono::duration`` → ``datetime.timedelta``
|
||||||
|
Durations are converted to timedeltas, any precision in the duration
|
||||||
|
greater than microseconds is lost by rounding towards zero.
|
||||||
|
|
||||||
|
- ``std::chrono::[other_clocks]::time_point`` → ``datetime.timedelta``
|
||||||
|
Any clock time that is not the system clock is converted to a time delta.
|
||||||
|
This timedelta measures the time from the clocks epoch to now.
|
||||||
|
|
||||||
|
.. rubric:: Python to C++
|
||||||
|
|
||||||
|
- ``datetime.datetime`` or ``datetime.date`` or ``datetime.time`` → ``std::chrono::system_clock::time_point``
|
||||||
|
Date/time objects are converted into system clock timepoints. Any
|
||||||
|
timezone information is ignored and the type is treated as a naive
|
||||||
|
object.
|
||||||
|
|
||||||
|
- ``datetime.timedelta`` → ``std::chrono::duration``
|
||||||
|
Time delta are converted into durations with microsecond precision.
|
||||||
|
|
||||||
|
- ``datetime.timedelta`` → ``std::chrono::[other_clocks]::time_point``
|
||||||
|
Time deltas that are converted into clock timepoints are treated as
|
||||||
|
the amount of time from the start of the clocks epoch.
|
||||||
|
|
||||||
|
- ``float`` → ``std::chrono::duration``
|
||||||
|
Floats that are passed to C++ as durations be interpreted as a number of
|
||||||
|
seconds. These will be converted to the duration using ``duration_cast``
|
||||||
|
from the float.
|
||||||
|
|
||||||
|
- ``float`` → ``std::chrono::[other_clocks]::time_point``
|
||||||
|
Floats that are passed to C++ as time points will be interpreted as the
|
||||||
|
number of seconds from the start of the clocks epoch.
|
91
3rdparty/pybind11/docs/advanced/cast/custom.rst
vendored
Normal file
91
3rdparty/pybind11/docs/advanced/cast/custom.rst
vendored
Normal file
@ -0,0 +1,91 @@
|
|||||||
|
Custom type casters
|
||||||
|
===================
|
||||||
|
|
||||||
|
In very rare cases, applications may require custom type casters that cannot be
|
||||||
|
expressed using the abstractions provided by pybind11, thus requiring raw
|
||||||
|
Python C API calls. This is fairly advanced usage and should only be pursued by
|
||||||
|
experts who are familiar with the intricacies of Python reference counting.
|
||||||
|
|
||||||
|
The following snippets demonstrate how this works for a very simple ``inty``
|
||||||
|
type that that should be convertible from Python types that provide a
|
||||||
|
``__int__(self)`` method.
|
||||||
|
|
||||||
|
.. code-block:: cpp
|
||||||
|
|
||||||
|
struct inty { long long_value; };
|
||||||
|
|
||||||
|
void print(inty s) {
|
||||||
|
std::cout << s.long_value << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
The following Python snippet demonstrates the intended usage from the Python side:
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
class A:
|
||||||
|
def __int__(self):
|
||||||
|
return 123
|
||||||
|
|
||||||
|
from example import print
|
||||||
|
print(A())
|
||||||
|
|
||||||
|
To register the necessary conversion routines, it is necessary to add
|
||||||
|
a partial overload to the ``pybind11::detail::type_caster<T>`` template.
|
||||||
|
Although this is an implementation detail, adding partial overloads to this
|
||||||
|
type is explicitly allowed.
|
||||||
|
|
||||||
|
.. code-block:: cpp
|
||||||
|
|
||||||
|
namespace pybind11 { namespace detail {
|
||||||
|
template <> struct type_caster<inty> {
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* This macro establishes the name 'inty' in
|
||||||
|
* function signatures and declares a local variable
|
||||||
|
* 'value' of type inty
|
||||||
|
*/
|
||||||
|
PYBIND11_TYPE_CASTER(inty, _("inty"));
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Conversion part 1 (Python->C++): convert a PyObject into a inty
|
||||||
|
* instance or return false upon failure. The second argument
|
||||||
|
* indicates whether implicit conversions should be applied.
|
||||||
|
*/
|
||||||
|
bool load(handle src, bool) {
|
||||||
|
/* Extract PyObject from handle */
|
||||||
|
PyObject *source = src.ptr();
|
||||||
|
/* Try converting into a Python integer value */
|
||||||
|
PyObject *tmp = PyNumber_Long(source);
|
||||||
|
if (!tmp)
|
||||||
|
return false;
|
||||||
|
/* Now try to convert into a C++ int */
|
||||||
|
value.long_value = PyLong_AsLong(tmp);
|
||||||
|
Py_DECREF(tmp);
|
||||||
|
/* Ensure return code was OK (to avoid out-of-range errors etc) */
|
||||||
|
return !(value.long_value == -1 && !PyErr_Occurred());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Conversion part 2 (C++ -> Python): convert an inty instance into
|
||||||
|
* a Python object. The second and third arguments are used to
|
||||||
|
* indicate the return value policy and parent object (for
|
||||||
|
* ``return_value_policy::reference_internal``) and are generally
|
||||||
|
* ignored by implicit casters.
|
||||||
|
*/
|
||||||
|
static handle cast(inty src, return_value_policy /* policy */, handle /* parent */) {
|
||||||
|
return PyLong_FromLong(src.long_value);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}} // namespace pybind11::detail
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
|
||||||
|
A ``type_caster<T>`` defined with ``PYBIND11_TYPE_CASTER(T, ...)`` requires
|
||||||
|
that ``T`` is default-constructible (``value`` is first default constructed
|
||||||
|
and then ``load()`` assigns to it).
|
||||||
|
|
||||||
|
.. warning::
|
||||||
|
|
||||||
|
When using custom type casters, it's important to declare them consistently
|
||||||
|
in every compilation unit of the Python extension module. Otherwise,
|
||||||
|
undefined behavior can ensue.
|
310
3rdparty/pybind11/docs/advanced/cast/eigen.rst
vendored
Normal file
310
3rdparty/pybind11/docs/advanced/cast/eigen.rst
vendored
Normal file
@ -0,0 +1,310 @@
|
|||||||
|
Eigen
|
||||||
|
#####
|
||||||
|
|
||||||
|
`Eigen <http://eigen.tuxfamily.org>`_ is C++ header-based library for dense and
|
||||||
|
sparse linear algebra. Due to its popularity and widespread adoption, pybind11
|
||||||
|
provides transparent conversion and limited mapping support between Eigen and
|
||||||
|
Scientific Python linear algebra data types.
|
||||||
|
|
||||||
|
To enable the built-in Eigen support you must include the optional header file
|
||||||
|
:file:`pybind11/eigen.h`.
|
||||||
|
|
||||||
|
Pass-by-value
|
||||||
|
=============
|
||||||
|
|
||||||
|
When binding a function with ordinary Eigen dense object arguments (for
|
||||||
|
example, ``Eigen::MatrixXd``), pybind11 will accept any input value that is
|
||||||
|
already (or convertible to) a ``numpy.ndarray`` with dimensions compatible with
|
||||||
|
the Eigen type, copy its values into a temporary Eigen variable of the
|
||||||
|
appropriate type, then call the function with this temporary variable.
|
||||||
|
|
||||||
|
Sparse matrices are similarly copied to or from
|
||||||
|
``scipy.sparse.csr_matrix``/``scipy.sparse.csc_matrix`` objects.
|
||||||
|
|
||||||
|
Pass-by-reference
|
||||||
|
=================
|
||||||
|
|
||||||
|
One major limitation of the above is that every data conversion implicitly
|
||||||
|
involves a copy, which can be both expensive (for large matrices) and disallows
|
||||||
|
binding functions that change their (Matrix) arguments. Pybind11 allows you to
|
||||||
|
work around this by using Eigen's ``Eigen::Ref<MatrixType>`` class much as you
|
||||||
|
would when writing a function taking a generic type in Eigen itself (subject to
|
||||||
|
some limitations discussed below).
|
||||||
|
|
||||||
|
When calling a bound function accepting a ``Eigen::Ref<const MatrixType>``
|
||||||
|
type, pybind11 will attempt to avoid copying by using an ``Eigen::Map`` object
|
||||||
|
that maps into the source ``numpy.ndarray`` data: this requires both that the
|
||||||
|
data types are the same (e.g. ``dtype='float64'`` and ``MatrixType::Scalar`` is
|
||||||
|
``double``); and that the storage is layout compatible. The latter limitation
|
||||||
|
is discussed in detail in the section below, and requires careful
|
||||||
|
consideration: by default, numpy matrices and Eigen matrices are *not* storage
|
||||||
|
compatible.
|
||||||
|
|
||||||
|
If the numpy matrix cannot be used as is (either because its types differ, e.g.
|
||||||
|
passing an array of integers to an Eigen parameter requiring doubles, or
|
||||||
|
because the storage is incompatible), pybind11 makes a temporary copy and
|
||||||
|
passes the copy instead.
|
||||||
|
|
||||||
|
When a bound function parameter is instead ``Eigen::Ref<MatrixType>`` (note the
|
||||||
|
lack of ``const``), pybind11 will only allow the function to be called if it
|
||||||
|
can be mapped *and* if the numpy array is writeable (that is
|
||||||
|
``a.flags.writeable`` is true). Any access (including modification) made to
|
||||||
|
the passed variable will be transparently carried out directly on the
|
||||||
|
``numpy.ndarray``.
|
||||||
|
|
||||||
|
This means you can can write code such as the following and have it work as
|
||||||
|
expected:
|
||||||
|
|
||||||
|
.. code-block:: cpp
|
||||||
|
|
||||||
|
void scale_by_2(Eigen::Ref<Eigen::VectorXd> v) {
|
||||||
|
v *= 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
Note, however, that you will likely run into limitations due to numpy and
|
||||||
|
Eigen's difference default storage order for data; see the below section on
|
||||||
|
:ref:`storage_orders` for details on how to bind code that won't run into such
|
||||||
|
limitations.
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
|
||||||
|
Passing by reference is not supported for sparse types.
|
||||||
|
|
||||||
|
Returning values to Python
|
||||||
|
==========================
|
||||||
|
|
||||||
|
When returning an ordinary dense Eigen matrix type to numpy (e.g.
|
||||||
|
``Eigen::MatrixXd`` or ``Eigen::RowVectorXf``) pybind11 keeps the matrix and
|
||||||
|
returns a numpy array that directly references the Eigen matrix: no copy of the
|
||||||
|
data is performed. The numpy array will have ``array.flags.owndata`` set to
|
||||||
|
``False`` to indicate that it does not own the data, and the lifetime of the
|
||||||
|
stored Eigen matrix will be tied to the returned ``array``.
|
||||||
|
|
||||||
|
If you bind a function with a non-reference, ``const`` return type (e.g.
|
||||||
|
``const Eigen::MatrixXd``), the same thing happens except that pybind11 also
|
||||||
|
sets the numpy array's ``writeable`` flag to false.
|
||||||
|
|
||||||
|
If you return an lvalue reference or pointer, the usual pybind11 rules apply,
|
||||||
|
as dictated by the binding function's return value policy (see the
|
||||||
|
documentation on :ref:`return_value_policies` for full details). That means,
|
||||||
|
without an explicit return value policy, lvalue references will be copied and
|
||||||
|
pointers will be managed by pybind11. In order to avoid copying, you should
|
||||||
|
explicitly specify an appropriate return value policy, as in the following
|
||||||
|
example:
|
||||||
|
|
||||||
|
.. code-block:: cpp
|
||||||
|
|
||||||
|
class MyClass {
|
||||||
|
Eigen::MatrixXd big_mat = Eigen::MatrixXd::Zero(10000, 10000);
|
||||||
|
public:
|
||||||
|
Eigen::MatrixXd &getMatrix() { return big_mat; }
|
||||||
|
const Eigen::MatrixXd &viewMatrix() { return big_mat; }
|
||||||
|
};
|
||||||
|
|
||||||
|
// Later, in binding code:
|
||||||
|
py::class_<MyClass>(m, "MyClass")
|
||||||
|
.def(py::init<>())
|
||||||
|
.def("copy_matrix", &MyClass::getMatrix) // Makes a copy!
|
||||||
|
.def("get_matrix", &MyClass::getMatrix, py::return_value_policy::reference_internal)
|
||||||
|
.def("view_matrix", &MyClass::viewMatrix, py::return_value_policy::reference_internal)
|
||||||
|
;
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
a = MyClass()
|
||||||
|
m = a.get_matrix() # flags.writeable = True, flags.owndata = False
|
||||||
|
v = a.view_matrix() # flags.writeable = False, flags.owndata = False
|
||||||
|
c = a.copy_matrix() # flags.writeable = True, flags.owndata = True
|
||||||
|
# m[5,6] and v[5,6] refer to the same element, c[5,6] does not.
|
||||||
|
|
||||||
|
Note in this example that ``py::return_value_policy::reference_internal`` is
|
||||||
|
used to tie the life of the MyClass object to the life of the returned arrays.
|
||||||
|
|
||||||
|
You may also return an ``Eigen::Ref``, ``Eigen::Map`` or other map-like Eigen
|
||||||
|
object (for example, the return value of ``matrix.block()`` and related
|
||||||
|
methods) that map into a dense Eigen type. When doing so, the default
|
||||||
|
behaviour of pybind11 is to simply reference the returned data: you must take
|
||||||
|
care to ensure that this data remains valid! You may ask pybind11 to
|
||||||
|
explicitly *copy* such a return value by using the
|
||||||
|
``py::return_value_policy::copy`` policy when binding the function. You may
|
||||||
|
also use ``py::return_value_policy::reference_internal`` or a
|
||||||
|
``py::keep_alive`` to ensure the data stays valid as long as the returned numpy
|
||||||
|
array does.
|
||||||
|
|
||||||
|
When returning such a reference of map, pybind11 additionally respects the
|
||||||
|
readonly-status of the returned value, marking the numpy array as non-writeable
|
||||||
|
if the reference or map was itself read-only.
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
|
||||||
|
Sparse types are always copied when returned.
|
||||||
|
|
||||||
|
.. _storage_orders:
|
||||||
|
|
||||||
|
Storage orders
|
||||||
|
==============
|
||||||
|
|
||||||
|
Passing arguments via ``Eigen::Ref`` has some limitations that you must be
|
||||||
|
aware of in order to effectively pass matrices by reference. First and
|
||||||
|
foremost is that the default ``Eigen::Ref<MatrixType>`` class requires
|
||||||
|
contiguous storage along columns (for column-major types, the default in Eigen)
|
||||||
|
or rows if ``MatrixType`` is specifically an ``Eigen::RowMajor`` storage type.
|
||||||
|
The former, Eigen's default, is incompatible with ``numpy``'s default row-major
|
||||||
|
storage, and so you will not be able to pass numpy arrays to Eigen by reference
|
||||||
|
without making one of two changes.
|
||||||
|
|
||||||
|
(Note that this does not apply to vectors (or column or row matrices): for such
|
||||||
|
types the "row-major" and "column-major" distinction is meaningless).
|
||||||
|
|
||||||
|
The first approach is to change the use of ``Eigen::Ref<MatrixType>`` to the
|
||||||
|
more general ``Eigen::Ref<MatrixType, 0, Eigen::Stride<Eigen::Dynamic,
|
||||||
|
Eigen::Dynamic>>`` (or similar type with a fully dynamic stride type in the
|
||||||
|
third template argument). Since this is a rather cumbersome type, pybind11
|
||||||
|
provides a ``py::EigenDRef<MatrixType>`` type alias for your convenience (along
|
||||||
|
with EigenDMap for the equivalent Map, and EigenDStride for just the stride
|
||||||
|
type).
|
||||||
|
|
||||||
|
This type allows Eigen to map into any arbitrary storage order. This is not
|
||||||
|
the default in Eigen for performance reasons: contiguous storage allows
|
||||||
|
vectorization that cannot be done when storage is not known to be contiguous at
|
||||||
|
compile time. The default ``Eigen::Ref`` stride type allows non-contiguous
|
||||||
|
storage along the outer dimension (that is, the rows of a column-major matrix
|
||||||
|
or columns of a row-major matrix), but not along the inner dimension.
|
||||||
|
|
||||||
|
This type, however, has the added benefit of also being able to map numpy array
|
||||||
|
slices. For example, the following (contrived) example uses Eigen with a numpy
|
||||||
|
slice to multiply by 2 all coefficients that are both on even rows (0, 2, 4,
|
||||||
|
...) and in columns 2, 5, or 8:
|
||||||
|
|
||||||
|
.. code-block:: cpp
|
||||||
|
|
||||||
|
m.def("scale", [](py::EigenDRef<Eigen::MatrixXd> m, double c) { m *= c; });
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
# a = np.array(...)
|
||||||
|
scale_by_2(myarray[0::2, 2:9:3])
|
||||||
|
|
||||||
|
The second approach to avoid copying is more intrusive: rearranging the
|
||||||
|
underlying data types to not run into the non-contiguous storage problem in the
|
||||||
|
first place. In particular, that means using matrices with ``Eigen::RowMajor``
|
||||||
|
storage, where appropriate, such as:
|
||||||
|
|
||||||
|
.. code-block:: cpp
|
||||||
|
|
||||||
|
using RowMatrixXd = Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor>;
|
||||||
|
// Use RowMatrixXd instead of MatrixXd
|
||||||
|
|
||||||
|
Now bound functions accepting ``Eigen::Ref<RowMatrixXd>`` arguments will be
|
||||||
|
callable with numpy's (default) arrays without involving a copying.
|
||||||
|
|
||||||
|
You can, alternatively, change the storage order that numpy arrays use by
|
||||||
|
adding the ``order='F'`` option when creating an array:
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
myarray = np.array(source, order='F')
|
||||||
|
|
||||||
|
Such an object will be passable to a bound function accepting an
|
||||||
|
``Eigen::Ref<MatrixXd>`` (or similar column-major Eigen type).
|
||||||
|
|
||||||
|
One major caveat with this approach, however, is that it is not entirely as
|
||||||
|
easy as simply flipping all Eigen or numpy usage from one to the other: some
|
||||||
|
operations may alter the storage order of a numpy array. For example, ``a2 =
|
||||||
|
array.transpose()`` results in ``a2`` being a view of ``array`` that references
|
||||||
|
the same data, but in the opposite storage order!
|
||||||
|
|
||||||
|
While this approach allows fully optimized vectorized calculations in Eigen, it
|
||||||
|
cannot be used with array slices, unlike the first approach.
|
||||||
|
|
||||||
|
When *returning* a matrix to Python (either a regular matrix, a reference via
|
||||||
|
``Eigen::Ref<>``, or a map/block into a matrix), no special storage
|
||||||
|
consideration is required: the created numpy array will have the required
|
||||||
|
stride that allows numpy to properly interpret the array, whatever its storage
|
||||||
|
order.
|
||||||
|
|
||||||
|
Failing rather than copying
|
||||||
|
===========================
|
||||||
|
|
||||||
|
The default behaviour when binding ``Eigen::Ref<const MatrixType>`` Eigen
|
||||||
|
references is to copy matrix values when passed a numpy array that does not
|
||||||
|
conform to the element type of ``MatrixType`` or does not have a compatible
|
||||||
|
stride layout. If you want to explicitly avoid copying in such a case, you
|
||||||
|
should bind arguments using the ``py::arg().noconvert()`` annotation (as
|
||||||
|
described in the :ref:`nonconverting_arguments` documentation).
|
||||||
|
|
||||||
|
The following example shows an example of arguments that don't allow data
|
||||||
|
copying to take place:
|
||||||
|
|
||||||
|
.. code-block:: cpp
|
||||||
|
|
||||||
|
// The method and function to be bound:
|
||||||
|
class MyClass {
|
||||||
|
// ...
|
||||||
|
double some_method(const Eigen::Ref<const MatrixXd> &matrix) { /* ... */ }
|
||||||
|
};
|
||||||
|
float some_function(const Eigen::Ref<const MatrixXf> &big,
|
||||||
|
const Eigen::Ref<const MatrixXf> &small) {
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
|
||||||
|
// The associated binding code:
|
||||||
|
using namespace pybind11::literals; // for "arg"_a
|
||||||
|
py::class_<MyClass>(m, "MyClass")
|
||||||
|
// ... other class definitions
|
||||||
|
.def("some_method", &MyClass::some_method, py::arg().noconvert());
|
||||||
|
|
||||||
|
m.def("some_function", &some_function,
|
||||||
|
"big"_a.noconvert(), // <- Don't allow copying for this arg
|
||||||
|
"small"_a // <- This one can be copied if needed
|
||||||
|
);
|
||||||
|
|
||||||
|
With the above binding code, attempting to call the the ``some_method(m)``
|
||||||
|
method on a ``MyClass`` object, or attempting to call ``some_function(m, m2)``
|
||||||
|
will raise a ``RuntimeError`` rather than making a temporary copy of the array.
|
||||||
|
It will, however, allow the ``m2`` argument to be copied into a temporary if
|
||||||
|
necessary.
|
||||||
|
|
||||||
|
Note that explicitly specifying ``.noconvert()`` is not required for *mutable*
|
||||||
|
Eigen references (e.g. ``Eigen::Ref<MatrixXd>`` without ``const`` on the
|
||||||
|
``MatrixXd``): mutable references will never be called with a temporary copy.
|
||||||
|
|
||||||
|
Vectors versus column/row matrices
|
||||||
|
==================================
|
||||||
|
|
||||||
|
Eigen and numpy have fundamentally different notions of a vector. In Eigen, a
|
||||||
|
vector is simply a matrix with the number of columns or rows set to 1 at
|
||||||
|
compile time (for a column vector or row vector, respectively). Numpy, in
|
||||||
|
contrast, has comparable 2-dimensional 1xN and Nx1 arrays, but *also* has
|
||||||
|
1-dimensional arrays of size N.
|
||||||
|
|
||||||
|
When passing a 2-dimensional 1xN or Nx1 array to Eigen, the Eigen type must
|
||||||
|
have matching dimensions: That is, you cannot pass a 2-dimensional Nx1 numpy
|
||||||
|
array to an Eigen value expecting a row vector, or a 1xN numpy array as a
|
||||||
|
column vector argument.
|
||||||
|
|
||||||
|
On the other hand, pybind11 allows you to pass 1-dimensional arrays of length N
|
||||||
|
as Eigen parameters. If the Eigen type can hold a column vector of length N it
|
||||||
|
will be passed as such a column vector. If not, but the Eigen type constraints
|
||||||
|
will accept a row vector, it will be passed as a row vector. (The column
|
||||||
|
vector takes precedence when both are supported, for example, when passing a
|
||||||
|
1D numpy array to a MatrixXd argument). Note that the type need not be
|
||||||
|
explicitly a vector: it is permitted to pass a 1D numpy array of size 5 to an
|
||||||
|
Eigen ``Matrix<double, Dynamic, 5>``: you would end up with a 1x5 Eigen matrix.
|
||||||
|
Passing the same to an ``Eigen::MatrixXd`` would result in a 5x1 Eigen matrix.
|
||||||
|
|
||||||
|
When returning an Eigen vector to numpy, the conversion is ambiguous: a row
|
||||||
|
vector of length 4 could be returned as either a 1D array of length 4, or as a
|
||||||
|
2D array of size 1x4. When encountering such a situation, pybind11 compromises
|
||||||
|
by considering the returned Eigen type: if it is a compile-time vector--that
|
||||||
|
is, the type has either the number of rows or columns set to 1 at compile
|
||||||
|
time--pybind11 converts to a 1D numpy array when returning the value. For
|
||||||
|
instances that are a vector only at run-time (e.g. ``MatrixXd``,
|
||||||
|
``Matrix<float, Dynamic, 4>``), pybind11 returns the vector as a 2D array to
|
||||||
|
numpy. If this isn't want you want, you can use ``array.reshape(...)`` to get
|
||||||
|
a view of the same data in the desired dimensions.
|
||||||
|
|
||||||
|
.. seealso::
|
||||||
|
|
||||||
|
The file :file:`tests/test_eigen.cpp` contains a complete example that
|
||||||
|
shows how to pass Eigen sparse and dense data types in more detail.
|
109
3rdparty/pybind11/docs/advanced/cast/functional.rst
vendored
Normal file
109
3rdparty/pybind11/docs/advanced/cast/functional.rst
vendored
Normal file
@ -0,0 +1,109 @@
|
|||||||
|
Functional
|
||||||
|
##########
|
||||||
|
|
||||||
|
The following features must be enabled by including :file:`pybind11/functional.h`.
|
||||||
|
|
||||||
|
|
||||||
|
Callbacks and passing anonymous functions
|
||||||
|
=========================================
|
||||||
|
|
||||||
|
The C++11 standard brought lambda functions and the generic polymorphic
|
||||||
|
function wrapper ``std::function<>`` to the C++ programming language, which
|
||||||
|
enable powerful new ways of working with functions. Lambda functions come in
|
||||||
|
two flavors: stateless lambda function resemble classic function pointers that
|
||||||
|
link to an anonymous piece of code, while stateful lambda functions
|
||||||
|
additionally depend on captured variables that are stored in an anonymous
|
||||||
|
*lambda closure object*.
|
||||||
|
|
||||||
|
Here is a simple example of a C++ function that takes an arbitrary function
|
||||||
|
(stateful or stateless) with signature ``int -> int`` as an argument and runs
|
||||||
|
it with the value 10.
|
||||||
|
|
||||||
|
.. code-block:: cpp
|
||||||
|
|
||||||
|
int func_arg(const std::function<int(int)> &f) {
|
||||||
|
return f(10);
|
||||||
|
}
|
||||||
|
|
||||||
|
The example below is more involved: it takes a function of signature ``int -> int``
|
||||||
|
and returns another function of the same kind. The return value is a stateful
|
||||||
|
lambda function, which stores the value ``f`` in the capture object and adds 1 to
|
||||||
|
its return value upon execution.
|
||||||
|
|
||||||
|
.. code-block:: cpp
|
||||||
|
|
||||||
|
std::function<int(int)> func_ret(const std::function<int(int)> &f) {
|
||||||
|
return [f](int i) {
|
||||||
|
return f(i) + 1;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
This example demonstrates using python named parameters in C++ callbacks which
|
||||||
|
requires using ``py::cpp_function`` as a wrapper. Usage is similar to defining
|
||||||
|
methods of classes:
|
||||||
|
|
||||||
|
.. code-block:: cpp
|
||||||
|
|
||||||
|
py::cpp_function func_cpp() {
|
||||||
|
return py::cpp_function([](int i) { return i+1; },
|
||||||
|
py::arg("number"));
|
||||||
|
}
|
||||||
|
|
||||||
|
After including the extra header file :file:`pybind11/functional.h`, it is almost
|
||||||
|
trivial to generate binding code for all of these functions.
|
||||||
|
|
||||||
|
.. code-block:: cpp
|
||||||
|
|
||||||
|
#include <pybind11/functional.h>
|
||||||
|
|
||||||
|
PYBIND11_MODULE(example, m) {
|
||||||
|
m.def("func_arg", &func_arg);
|
||||||
|
m.def("func_ret", &func_ret);
|
||||||
|
m.def("func_cpp", &func_cpp);
|
||||||
|
}
|
||||||
|
|
||||||
|
The following interactive session shows how to call them from Python.
|
||||||
|
|
||||||
|
.. code-block:: pycon
|
||||||
|
|
||||||
|
$ python
|
||||||
|
>>> import example
|
||||||
|
>>> def square(i):
|
||||||
|
... return i * i
|
||||||
|
...
|
||||||
|
>>> example.func_arg(square)
|
||||||
|
100L
|
||||||
|
>>> square_plus_1 = example.func_ret(square)
|
||||||
|
>>> square_plus_1(4)
|
||||||
|
17L
|
||||||
|
>>> plus_1 = func_cpp()
|
||||||
|
>>> plus_1(number=43)
|
||||||
|
44L
|
||||||
|
|
||||||
|
.. warning::
|
||||||
|
|
||||||
|
Keep in mind that passing a function from C++ to Python (or vice versa)
|
||||||
|
will instantiate a piece of wrapper code that translates function
|
||||||
|
invocations between the two languages. Naturally, this translation
|
||||||
|
increases the computational cost of each function call somewhat. A
|
||||||
|
problematic situation can arise when a function is copied back and forth
|
||||||
|
between Python and C++ many times in a row, in which case the underlying
|
||||||
|
wrappers will accumulate correspondingly. The resulting long sequence of
|
||||||
|
C++ -> Python -> C++ -> ... roundtrips can significantly decrease
|
||||||
|
performance.
|
||||||
|
|
||||||
|
There is one exception: pybind11 detects case where a stateless function
|
||||||
|
(i.e. a function pointer or a lambda function without captured variables)
|
||||||
|
is passed as an argument to another C++ function exposed in Python. In this
|
||||||
|
case, there is no overhead. Pybind11 will extract the underlying C++
|
||||||
|
function pointer from the wrapped function to sidestep a potential C++ ->
|
||||||
|
Python -> C++ roundtrip. This is demonstrated in :file:`tests/test_callbacks.cpp`.
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
|
||||||
|
This functionality is very useful when generating bindings for callbacks in
|
||||||
|
C++ libraries (e.g. GUI libraries, asynchronous networking libraries, etc.).
|
||||||
|
|
||||||
|
The file :file:`tests/test_callbacks.cpp` contains a complete example
|
||||||
|
that demonstrates how to work with callbacks and anonymous functions in
|
||||||
|
more detail.
|
42
3rdparty/pybind11/docs/advanced/cast/index.rst
vendored
Normal file
42
3rdparty/pybind11/docs/advanced/cast/index.rst
vendored
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
Type conversions
|
||||||
|
################
|
||||||
|
|
||||||
|
Apart from enabling cross-language function calls, a fundamental problem
|
||||||
|
that a binding tool like pybind11 must address is to provide access to
|
||||||
|
native Python types in C++ and vice versa. There are three fundamentally
|
||||||
|
different ways to do this—which approach is preferable for a particular type
|
||||||
|
depends on the situation at hand.
|
||||||
|
|
||||||
|
1. Use a native C++ type everywhere. In this case, the type must be wrapped
|
||||||
|
using pybind11-generated bindings so that Python can interact with it.
|
||||||
|
|
||||||
|
2. Use a native Python type everywhere. It will need to be wrapped so that
|
||||||
|
C++ functions can interact with it.
|
||||||
|
|
||||||
|
3. Use a native C++ type on the C++ side and a native Python type on the
|
||||||
|
Python side. pybind11 refers to this as a *type conversion*.
|
||||||
|
|
||||||
|
Type conversions are the most "natural" option in the sense that native
|
||||||
|
(non-wrapped) types are used everywhere. The main downside is that a copy
|
||||||
|
of the data must be made on every Python ↔ C++ transition: this is
|
||||||
|
needed since the C++ and Python versions of the same type generally won't
|
||||||
|
have the same memory layout.
|
||||||
|
|
||||||
|
pybind11 can perform many kinds of conversions automatically. An overview
|
||||||
|
is provided in the table ":ref:`conversion_table`".
|
||||||
|
|
||||||
|
The following subsections discuss the differences between these options in more
|
||||||
|
detail. The main focus in this section is on type conversions, which represent
|
||||||
|
the last case of the above list.
|
||||||
|
|
||||||
|
.. toctree::
|
||||||
|
:maxdepth: 1
|
||||||
|
|
||||||
|
overview
|
||||||
|
strings
|
||||||
|
stl
|
||||||
|
functional
|
||||||
|
chrono
|
||||||
|
eigen
|
||||||
|
custom
|
||||||
|
|
165
3rdparty/pybind11/docs/advanced/cast/overview.rst
vendored
Normal file
165
3rdparty/pybind11/docs/advanced/cast/overview.rst
vendored
Normal file
@ -0,0 +1,165 @@
|
|||||||
|
Overview
|
||||||
|
########
|
||||||
|
|
||||||
|
.. rubric:: 1. Native type in C++, wrapper in Python
|
||||||
|
|
||||||
|
Exposing a custom C++ type using :class:`py::class_` was covered in detail
|
||||||
|
in the :doc:`/classes` section. There, the underlying data structure is
|
||||||
|
always the original C++ class while the :class:`py::class_` wrapper provides
|
||||||
|
a Python interface. Internally, when an object like this is sent from C++ to
|
||||||
|
Python, pybind11 will just add the outer wrapper layer over the native C++
|
||||||
|
object. Getting it back from Python is just a matter of peeling off the
|
||||||
|
wrapper.
|
||||||
|
|
||||||
|
.. rubric:: 2. Wrapper in C++, native type in Python
|
||||||
|
|
||||||
|
This is the exact opposite situation. Now, we have a type which is native to
|
||||||
|
Python, like a ``tuple`` or a ``list``. One way to get this data into C++ is
|
||||||
|
with the :class:`py::object` family of wrappers. These are explained in more
|
||||||
|
detail in the :doc:`/advanced/pycpp/object` section. We'll just give a quick
|
||||||
|
example here:
|
||||||
|
|
||||||
|
.. code-block:: cpp
|
||||||
|
|
||||||
|
void print_list(py::list my_list) {
|
||||||
|
for (auto item : my_list)
|
||||||
|
std::cout << item << " ";
|
||||||
|
}
|
||||||
|
|
||||||
|
.. code-block:: pycon
|
||||||
|
|
||||||
|
>>> print_list([1, 2, 3])
|
||||||
|
1 2 3
|
||||||
|
|
||||||
|
The Python ``list`` is not converted in any way -- it's just wrapped in a C++
|
||||||
|
:class:`py::list` class. At its core it's still a Python object. Copying a
|
||||||
|
:class:`py::list` will do the usual reference-counting like in Python.
|
||||||
|
Returning the object to Python will just remove the thin wrapper.
|
||||||
|
|
||||||
|
.. rubric:: 3. Converting between native C++ and Python types
|
||||||
|
|
||||||
|
In the previous two cases we had a native type in one language and a wrapper in
|
||||||
|
the other. Now, we have native types on both sides and we convert between them.
|
||||||
|
|
||||||
|
.. code-block:: cpp
|
||||||
|
|
||||||
|
void print_vector(const std::vector<int> &v) {
|
||||||
|
for (auto item : v)
|
||||||
|
std::cout << item << "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
.. code-block:: pycon
|
||||||
|
|
||||||
|
>>> print_vector([1, 2, 3])
|
||||||
|
1 2 3
|
||||||
|
|
||||||
|
In this case, pybind11 will construct a new ``std::vector<int>`` and copy each
|
||||||
|
element from the Python ``list``. The newly constructed object will be passed
|
||||||
|
to ``print_vector``. The same thing happens in the other direction: a new
|
||||||
|
``list`` is made to match the value returned from C++.
|
||||||
|
|
||||||
|
Lots of these conversions are supported out of the box, as shown in the table
|
||||||
|
below. They are very convenient, but keep in mind that these conversions are
|
||||||
|
fundamentally based on copying data. This is perfectly fine for small immutable
|
||||||
|
types but it may become quite expensive for large data structures. This can be
|
||||||
|
avoided by overriding the automatic conversion with a custom wrapper (i.e. the
|
||||||
|
above-mentioned approach 1). This requires some manual effort and more details
|
||||||
|
are available in the :ref:`opaque` section.
|
||||||
|
|
||||||
|
.. _conversion_table:
|
||||||
|
|
||||||
|
List of all builtin conversions
|
||||||
|
-------------------------------
|
||||||
|
|
||||||
|
The following basic data types are supported out of the box (some may require
|
||||||
|
an additional extension header to be included). To pass other data structures
|
||||||
|
as arguments and return values, refer to the section on binding :ref:`classes`.
|
||||||
|
|
||||||
|
+------------------------------------+---------------------------+-------------------------------+
|
||||||
|
| Data type | Description | Header file |
|
||||||
|
+====================================+===========================+===============================+
|
||||||
|
| ``int8_t``, ``uint8_t`` | 8-bit integers | :file:`pybind11/pybind11.h` |
|
||||||
|
+------------------------------------+---------------------------+-------------------------------+
|
||||||
|
| ``int16_t``, ``uint16_t`` | 16-bit integers | :file:`pybind11/pybind11.h` |
|
||||||
|
+------------------------------------+---------------------------+-------------------------------+
|
||||||
|
| ``int32_t``, ``uint32_t`` | 32-bit integers | :file:`pybind11/pybind11.h` |
|
||||||
|
+------------------------------------+---------------------------+-------------------------------+
|
||||||
|
| ``int64_t``, ``uint64_t`` | 64-bit integers | :file:`pybind11/pybind11.h` |
|
||||||
|
+------------------------------------+---------------------------+-------------------------------+
|
||||||
|
| ``ssize_t``, ``size_t`` | Platform-dependent size | :file:`pybind11/pybind11.h` |
|
||||||
|
+------------------------------------+---------------------------+-------------------------------+
|
||||||
|
| ``float``, ``double`` | Floating point types | :file:`pybind11/pybind11.h` |
|
||||||
|
+------------------------------------+---------------------------+-------------------------------+
|
||||||
|
| ``bool`` | Two-state Boolean type | :file:`pybind11/pybind11.h` |
|
||||||
|
+------------------------------------+---------------------------+-------------------------------+
|
||||||
|
| ``char`` | Character literal | :file:`pybind11/pybind11.h` |
|
||||||
|
+------------------------------------+---------------------------+-------------------------------+
|
||||||
|
| ``char16_t`` | UTF-16 character literal | :file:`pybind11/pybind11.h` |
|
||||||
|
+------------------------------------+---------------------------+-------------------------------+
|
||||||
|
| ``char32_t`` | UTF-32 character literal | :file:`pybind11/pybind11.h` |
|
||||||
|
+------------------------------------+---------------------------+-------------------------------+
|
||||||
|
| ``wchar_t`` | Wide character literal | :file:`pybind11/pybind11.h` |
|
||||||
|
+------------------------------------+---------------------------+-------------------------------+
|
||||||
|
| ``const char *`` | UTF-8 string literal | :file:`pybind11/pybind11.h` |
|
||||||
|
+------------------------------------+---------------------------+-------------------------------+
|
||||||
|
| ``const char16_t *`` | UTF-16 string literal | :file:`pybind11/pybind11.h` |
|
||||||
|
+------------------------------------+---------------------------+-------------------------------+
|
||||||
|
| ``const char32_t *`` | UTF-32 string literal | :file:`pybind11/pybind11.h` |
|
||||||
|
+------------------------------------+---------------------------+-------------------------------+
|
||||||
|
| ``const wchar_t *`` | Wide string literal | :file:`pybind11/pybind11.h` |
|
||||||
|
+------------------------------------+---------------------------+-------------------------------+
|
||||||
|
| ``std::string`` | STL dynamic UTF-8 string | :file:`pybind11/pybind11.h` |
|
||||||
|
+------------------------------------+---------------------------+-------------------------------+
|
||||||
|
| ``std::u16string`` | STL dynamic UTF-16 string | :file:`pybind11/pybind11.h` |
|
||||||
|
+------------------------------------+---------------------------+-------------------------------+
|
||||||
|
| ``std::u32string`` | STL dynamic UTF-32 string | :file:`pybind11/pybind11.h` |
|
||||||
|
+------------------------------------+---------------------------+-------------------------------+
|
||||||
|
| ``std::wstring`` | STL dynamic wide string | :file:`pybind11/pybind11.h` |
|
||||||
|
+------------------------------------+---------------------------+-------------------------------+
|
||||||
|
| ``std::string_view``, | STL C++17 string views | :file:`pybind11/pybind11.h` |
|
||||||
|
| ``std::u16string_view``, etc. | | |
|
||||||
|
+------------------------------------+---------------------------+-------------------------------+
|
||||||
|
| ``std::pair<T1, T2>`` | Pair of two custom types | :file:`pybind11/pybind11.h` |
|
||||||
|
+------------------------------------+---------------------------+-------------------------------+
|
||||||
|
| ``std::tuple<...>`` | Arbitrary tuple of types | :file:`pybind11/pybind11.h` |
|
||||||
|
+------------------------------------+---------------------------+-------------------------------+
|
||||||
|
| ``std::reference_wrapper<...>`` | Reference type wrapper | :file:`pybind11/pybind11.h` |
|
||||||
|
+------------------------------------+---------------------------+-------------------------------+
|
||||||
|
| ``std::complex<T>`` | Complex numbers | :file:`pybind11/complex.h` |
|
||||||
|
+------------------------------------+---------------------------+-------------------------------+
|
||||||
|
| ``std::array<T, Size>`` | STL static array | :file:`pybind11/stl.h` |
|
||||||
|
+------------------------------------+---------------------------+-------------------------------+
|
||||||
|
| ``std::vector<T>`` | STL dynamic array | :file:`pybind11/stl.h` |
|
||||||
|
+------------------------------------+---------------------------+-------------------------------+
|
||||||
|
| ``std::deque<T>`` | STL double-ended queue | :file:`pybind11/stl.h` |
|
||||||
|
+------------------------------------+---------------------------+-------------------------------+
|
||||||
|
| ``std::valarray<T>`` | STL value array | :file:`pybind11/stl.h` |
|
||||||
|
+------------------------------------+---------------------------+-------------------------------+
|
||||||
|
| ``std::list<T>`` | STL linked list | :file:`pybind11/stl.h` |
|
||||||
|
+------------------------------------+---------------------------+-------------------------------+
|
||||||
|
| ``std::map<T1, T2>`` | STL ordered map | :file:`pybind11/stl.h` |
|
||||||
|
+------------------------------------+---------------------------+-------------------------------+
|
||||||
|
| ``std::unordered_map<T1, T2>`` | STL unordered map | :file:`pybind11/stl.h` |
|
||||||
|
+------------------------------------+---------------------------+-------------------------------+
|
||||||
|
| ``std::set<T>`` | STL ordered set | :file:`pybind11/stl.h` |
|
||||||
|
+------------------------------------+---------------------------+-------------------------------+
|
||||||
|
| ``std::unordered_set<T>`` | STL unordered set | :file:`pybind11/stl.h` |
|
||||||
|
+------------------------------------+---------------------------+-------------------------------+
|
||||||
|
| ``std::optional<T>`` | STL optional type (C++17) | :file:`pybind11/stl.h` |
|
||||||
|
+------------------------------------+---------------------------+-------------------------------+
|
||||||
|
| ``std::experimental::optional<T>`` | STL optional type (exp.) | :file:`pybind11/stl.h` |
|
||||||
|
+------------------------------------+---------------------------+-------------------------------+
|
||||||
|
| ``std::variant<...>`` | Type-safe union (C++17) | :file:`pybind11/stl.h` |
|
||||||
|
+------------------------------------+---------------------------+-------------------------------+
|
||||||
|
| ``std::function<...>`` | STL polymorphic function | :file:`pybind11/functional.h` |
|
||||||
|
+------------------------------------+---------------------------+-------------------------------+
|
||||||
|
| ``std::chrono::duration<...>`` | STL time duration | :file:`pybind11/chrono.h` |
|
||||||
|
+------------------------------------+---------------------------+-------------------------------+
|
||||||
|
| ``std::chrono::time_point<...>`` | STL date/time | :file:`pybind11/chrono.h` |
|
||||||
|
+------------------------------------+---------------------------+-------------------------------+
|
||||||
|
| ``Eigen::Matrix<...>`` | Eigen: dense matrix | :file:`pybind11/eigen.h` |
|
||||||
|
+------------------------------------+---------------------------+-------------------------------+
|
||||||
|
| ``Eigen::Map<...>`` | Eigen: mapped memory | :file:`pybind11/eigen.h` |
|
||||||
|
+------------------------------------+---------------------------+-------------------------------+
|
||||||
|
| ``Eigen::SparseMatrix<...>`` | Eigen: sparse matrix | :file:`pybind11/eigen.h` |
|
||||||
|
+------------------------------------+---------------------------+-------------------------------+
|
240
3rdparty/pybind11/docs/advanced/cast/stl.rst
vendored
Normal file
240
3rdparty/pybind11/docs/advanced/cast/stl.rst
vendored
Normal file
@ -0,0 +1,240 @@
|
|||||||
|
STL containers
|
||||||
|
##############
|
||||||
|
|
||||||
|
Automatic conversion
|
||||||
|
====================
|
||||||
|
|
||||||
|
When including the additional header file :file:`pybind11/stl.h`, conversions
|
||||||
|
between ``std::vector<>``/``std::deque<>``/``std::list<>``/``std::array<>``,
|
||||||
|
``std::set<>``/``std::unordered_set<>``, and
|
||||||
|
``std::map<>``/``std::unordered_map<>`` and the Python ``list``, ``set`` and
|
||||||
|
``dict`` data structures are automatically enabled. The types ``std::pair<>``
|
||||||
|
and ``std::tuple<>`` are already supported out of the box with just the core
|
||||||
|
:file:`pybind11/pybind11.h` header.
|
||||||
|
|
||||||
|
The major downside of these implicit conversions is that containers must be
|
||||||
|
converted (i.e. copied) on every Python->C++ and C++->Python transition, which
|
||||||
|
can have implications on the program semantics and performance. Please read the
|
||||||
|
next sections for more details and alternative approaches that avoid this.
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
|
||||||
|
Arbitrary nesting of any of these types is possible.
|
||||||
|
|
||||||
|
.. seealso::
|
||||||
|
|
||||||
|
The file :file:`tests/test_stl.cpp` contains a complete
|
||||||
|
example that demonstrates how to pass STL data types in more detail.
|
||||||
|
|
||||||
|
.. _cpp17_container_casters:
|
||||||
|
|
||||||
|
C++17 library containers
|
||||||
|
========================
|
||||||
|
|
||||||
|
The :file:`pybind11/stl.h` header also includes support for ``std::optional<>``
|
||||||
|
and ``std::variant<>``. These require a C++17 compiler and standard library.
|
||||||
|
In C++14 mode, ``std::experimental::optional<>`` is supported if available.
|
||||||
|
|
||||||
|
Various versions of these containers also exist for C++11 (e.g. in Boost).
|
||||||
|
pybind11 provides an easy way to specialize the ``type_caster`` for such
|
||||||
|
types:
|
||||||
|
|
||||||
|
.. code-block:: cpp
|
||||||
|
|
||||||
|
// `boost::optional` as an example -- can be any `std::optional`-like container
|
||||||
|
namespace pybind11 { namespace detail {
|
||||||
|
template <typename T>
|
||||||
|
struct type_caster<boost::optional<T>> : optional_caster<boost::optional<T>> {};
|
||||||
|
}}
|
||||||
|
|
||||||
|
The above should be placed in a header file and included in all translation units
|
||||||
|
where automatic conversion is needed. Similarly, a specialization can be provided
|
||||||
|
for custom variant types:
|
||||||
|
|
||||||
|
.. code-block:: cpp
|
||||||
|
|
||||||
|
// `boost::variant` as an example -- can be any `std::variant`-like container
|
||||||
|
namespace pybind11 { namespace detail {
|
||||||
|
template <typename... Ts>
|
||||||
|
struct type_caster<boost::variant<Ts...>> : variant_caster<boost::variant<Ts...>> {};
|
||||||
|
|
||||||
|
// Specifies the function used to visit the variant -- `apply_visitor` instead of `visit`
|
||||||
|
template <>
|
||||||
|
struct visit_helper<boost::variant> {
|
||||||
|
template <typename... Args>
|
||||||
|
static auto call(Args &&...args) -> decltype(boost::apply_visitor(args...)) {
|
||||||
|
return boost::apply_visitor(args...);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}} // namespace pybind11::detail
|
||||||
|
|
||||||
|
The ``visit_helper`` specialization is not required if your ``name::variant`` provides
|
||||||
|
a ``name::visit()`` function. For any other function name, the specialization must be
|
||||||
|
included to tell pybind11 how to visit the variant.
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
|
||||||
|
pybind11 only supports the modern implementation of ``boost::variant``
|
||||||
|
which makes use of variadic templates. This requires Boost 1.56 or newer.
|
||||||
|
Additionally, on Windows, MSVC 2017 is required because ``boost::variant``
|
||||||
|
falls back to the old non-variadic implementation on MSVC 2015.
|
||||||
|
|
||||||
|
.. _opaque:
|
||||||
|
|
||||||
|
Making opaque types
|
||||||
|
===================
|
||||||
|
|
||||||
|
pybind11 heavily relies on a template matching mechanism to convert parameters
|
||||||
|
and return values that are constructed from STL data types such as vectors,
|
||||||
|
linked lists, hash tables, etc. This even works in a recursive manner, for
|
||||||
|
instance to deal with lists of hash maps of pairs of elementary and custom
|
||||||
|
types, etc.
|
||||||
|
|
||||||
|
However, a fundamental limitation of this approach is that internal conversions
|
||||||
|
between Python and C++ types involve a copy operation that prevents
|
||||||
|
pass-by-reference semantics. What does this mean?
|
||||||
|
|
||||||
|
Suppose we bind the following function
|
||||||
|
|
||||||
|
.. code-block:: cpp
|
||||||
|
|
||||||
|
void append_1(std::vector<int> &v) {
|
||||||
|
v.push_back(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
and call it from Python, the following happens:
|
||||||
|
|
||||||
|
.. code-block:: pycon
|
||||||
|
|
||||||
|
>>> v = [5, 6]
|
||||||
|
>>> append_1(v)
|
||||||
|
>>> print(v)
|
||||||
|
[5, 6]
|
||||||
|
|
||||||
|
As you can see, when passing STL data structures by reference, modifications
|
||||||
|
are not propagated back the Python side. A similar situation arises when
|
||||||
|
exposing STL data structures using the ``def_readwrite`` or ``def_readonly``
|
||||||
|
functions:
|
||||||
|
|
||||||
|
.. code-block:: cpp
|
||||||
|
|
||||||
|
/* ... definition ... */
|
||||||
|
|
||||||
|
class MyClass {
|
||||||
|
std::vector<int> contents;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* ... binding code ... */
|
||||||
|
|
||||||
|
py::class_<MyClass>(m, "MyClass")
|
||||||
|
.def(py::init<>())
|
||||||
|
.def_readwrite("contents", &MyClass::contents);
|
||||||
|
|
||||||
|
In this case, properties can be read and written in their entirety. However, an
|
||||||
|
``append`` operation involving such a list type has no effect:
|
||||||
|
|
||||||
|
.. code-block:: pycon
|
||||||
|
|
||||||
|
>>> m = MyClass()
|
||||||
|
>>> m.contents = [5, 6]
|
||||||
|
>>> print(m.contents)
|
||||||
|
[5, 6]
|
||||||
|
>>> m.contents.append(7)
|
||||||
|
>>> print(m.contents)
|
||||||
|
[5, 6]
|
||||||
|
|
||||||
|
Finally, the involved copy operations can be costly when dealing with very
|
||||||
|
large lists. To deal with all of the above situations, pybind11 provides a
|
||||||
|
macro named ``PYBIND11_MAKE_OPAQUE(T)`` that disables the template-based
|
||||||
|
conversion machinery of types, thus rendering them *opaque*. The contents of
|
||||||
|
opaque objects are never inspected or extracted, hence they *can* be passed by
|
||||||
|
reference. For instance, to turn ``std::vector<int>`` into an opaque type, add
|
||||||
|
the declaration
|
||||||
|
|
||||||
|
.. code-block:: cpp
|
||||||
|
|
||||||
|
PYBIND11_MAKE_OPAQUE(std::vector<int>);
|
||||||
|
|
||||||
|
before any binding code (e.g. invocations to ``class_::def()``, etc.). This
|
||||||
|
macro must be specified at the top level (and outside of any namespaces), since
|
||||||
|
it instantiates a partial template overload. If your binding code consists of
|
||||||
|
multiple compilation units, it must be present in every file (typically via a
|
||||||
|
common header) preceding any usage of ``std::vector<int>``. Opaque types must
|
||||||
|
also have a corresponding ``class_`` declaration to associate them with a name
|
||||||
|
in Python, and to define a set of available operations, e.g.:
|
||||||
|
|
||||||
|
.. code-block:: cpp
|
||||||
|
|
||||||
|
py::class_<std::vector<int>>(m, "IntVector")
|
||||||
|
.def(py::init<>())
|
||||||
|
.def("clear", &std::vector<int>::clear)
|
||||||
|
.def("pop_back", &std::vector<int>::pop_back)
|
||||||
|
.def("__len__", [](const std::vector<int> &v) { return v.size(); })
|
||||||
|
.def("__iter__", [](std::vector<int> &v) {
|
||||||
|
return py::make_iterator(v.begin(), v.end());
|
||||||
|
}, py::keep_alive<0, 1>()) /* Keep vector alive while iterator is used */
|
||||||
|
// ....
|
||||||
|
|
||||||
|
.. seealso::
|
||||||
|
|
||||||
|
The file :file:`tests/test_opaque_types.cpp` contains a complete
|
||||||
|
example that demonstrates how to create and expose opaque types using
|
||||||
|
pybind11 in more detail.
|
||||||
|
|
||||||
|
.. _stl_bind:
|
||||||
|
|
||||||
|
Binding STL containers
|
||||||
|
======================
|
||||||
|
|
||||||
|
The ability to expose STL containers as native Python objects is a fairly
|
||||||
|
common request, hence pybind11 also provides an optional header file named
|
||||||
|
:file:`pybind11/stl_bind.h` that does exactly this. The mapped containers try
|
||||||
|
to match the behavior of their native Python counterparts as much as possible.
|
||||||
|
|
||||||
|
The following example showcases usage of :file:`pybind11/stl_bind.h`:
|
||||||
|
|
||||||
|
.. code-block:: cpp
|
||||||
|
|
||||||
|
// Don't forget this
|
||||||
|
#include <pybind11/stl_bind.h>
|
||||||
|
|
||||||
|
PYBIND11_MAKE_OPAQUE(std::vector<int>);
|
||||||
|
PYBIND11_MAKE_OPAQUE(std::map<std::string, double>);
|
||||||
|
|
||||||
|
// ...
|
||||||
|
|
||||||
|
// later in binding code:
|
||||||
|
py::bind_vector<std::vector<int>>(m, "VectorInt");
|
||||||
|
py::bind_map<std::map<std::string, double>>(m, "MapStringDouble");
|
||||||
|
|
||||||
|
When binding STL containers pybind11 considers the types of the container's
|
||||||
|
elements to decide whether the container should be confined to the local module
|
||||||
|
(via the :ref:`module_local` feature). If the container element types are
|
||||||
|
anything other than already-bound custom types bound without
|
||||||
|
``py::module_local()`` the container binding will have ``py::module_local()``
|
||||||
|
applied. This includes converting types such as numeric types, strings, Eigen
|
||||||
|
types; and types that have not yet been bound at the time of the stl container
|
||||||
|
binding. This module-local binding is designed to avoid potential conflicts
|
||||||
|
between module bindings (for example, from two separate modules each attempting
|
||||||
|
to bind ``std::vector<int>`` as a python type).
|
||||||
|
|
||||||
|
It is possible to override this behavior to force a definition to be either
|
||||||
|
module-local or global. To do so, you can pass the attributes
|
||||||
|
``py::module_local()`` (to make the binding module-local) or
|
||||||
|
``py::module_local(false)`` (to make the binding global) into the
|
||||||
|
``py::bind_vector`` or ``py::bind_map`` arguments:
|
||||||
|
|
||||||
|
.. code-block:: cpp
|
||||||
|
|
||||||
|
py::bind_vector<std::vector<int>>(m, "VectorInt", py::module_local(false));
|
||||||
|
|
||||||
|
Note, however, that such a global binding would make it impossible to load this
|
||||||
|
module at the same time as any other pybind module that also attempts to bind
|
||||||
|
the same container type (``std::vector<int>`` in the above example).
|
||||||
|
|
||||||
|
See :ref:`module_local` for more details on module-local bindings.
|
||||||
|
|
||||||
|
.. seealso::
|
||||||
|
|
||||||
|
The file :file:`tests/test_stl_binders.cpp` shows how to use the
|
||||||
|
convenience STL container wrappers.
|
305
3rdparty/pybind11/docs/advanced/cast/strings.rst
vendored
Normal file
305
3rdparty/pybind11/docs/advanced/cast/strings.rst
vendored
Normal file
@ -0,0 +1,305 @@
|
|||||||
|
Strings, bytes and Unicode conversions
|
||||||
|
######################################
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
|
||||||
|
This section discusses string handling in terms of Python 3 strings. For
|
||||||
|
Python 2.7, replace all occurrences of ``str`` with ``unicode`` and
|
||||||
|
``bytes`` with ``str``. Python 2.7 users may find it best to use ``from
|
||||||
|
__future__ import unicode_literals`` to avoid unintentionally using ``str``
|
||||||
|
instead of ``unicode``.
|
||||||
|
|
||||||
|
Passing Python strings to C++
|
||||||
|
=============================
|
||||||
|
|
||||||
|
When a Python ``str`` is passed from Python to a C++ function that accepts
|
||||||
|
``std::string`` or ``char *`` as arguments, pybind11 will encode the Python
|
||||||
|
string to UTF-8. All Python ``str`` can be encoded in UTF-8, so this operation
|
||||||
|
does not fail.
|
||||||
|
|
||||||
|
The C++ language is encoding agnostic. It is the responsibility of the
|
||||||
|
programmer to track encodings. It's often easiest to simply `use UTF-8
|
||||||
|
everywhere <http://utf8everywhere.org/>`_.
|
||||||
|
|
||||||
|
.. code-block:: c++
|
||||||
|
|
||||||
|
m.def("utf8_test",
|
||||||
|
[](const std::string &s) {
|
||||||
|
cout << "utf-8 is icing on the cake.\n";
|
||||||
|
cout << s;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
m.def("utf8_charptr",
|
||||||
|
[](const char *s) {
|
||||||
|
cout << "My favorite food is\n";
|
||||||
|
cout << s;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
>>> utf8_test('🎂')
|
||||||
|
utf-8 is icing on the cake.
|
||||||
|
🎂
|
||||||
|
|
||||||
|
>>> utf8_charptr('🍕')
|
||||||
|
My favorite food is
|
||||||
|
🍕
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
|
||||||
|
Some terminal emulators do not support UTF-8 or emoji fonts and may not
|
||||||
|
display the example above correctly.
|
||||||
|
|
||||||
|
The results are the same whether the C++ function accepts arguments by value or
|
||||||
|
reference, and whether or not ``const`` is used.
|
||||||
|
|
||||||
|
Passing bytes to C++
|
||||||
|
--------------------
|
||||||
|
|
||||||
|
A Python ``bytes`` object will be passed to C++ functions that accept
|
||||||
|
``std::string`` or ``char*`` *without* conversion. On Python 3, in order to
|
||||||
|
make a function *only* accept ``bytes`` (and not ``str``), declare it as taking
|
||||||
|
a ``py::bytes`` argument.
|
||||||
|
|
||||||
|
|
||||||
|
Returning C++ strings to Python
|
||||||
|
===============================
|
||||||
|
|
||||||
|
When a C++ function returns a ``std::string`` or ``char*`` to a Python caller,
|
||||||
|
**pybind11 will assume that the string is valid UTF-8** and will decode it to a
|
||||||
|
native Python ``str``, using the same API as Python uses to perform
|
||||||
|
``bytes.decode('utf-8')``. If this implicit conversion fails, pybind11 will
|
||||||
|
raise a ``UnicodeDecodeError``.
|
||||||
|
|
||||||
|
.. code-block:: c++
|
||||||
|
|
||||||
|
m.def("std_string_return",
|
||||||
|
[]() {
|
||||||
|
return std::string("This string needs to be UTF-8 encoded");
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
>>> isinstance(example.std_string_return(), str)
|
||||||
|
True
|
||||||
|
|
||||||
|
|
||||||
|
Because UTF-8 is inclusive of pure ASCII, there is never any issue with
|
||||||
|
returning a pure ASCII string to Python. If there is any possibility that the
|
||||||
|
string is not pure ASCII, it is necessary to ensure the encoding is valid
|
||||||
|
UTF-8.
|
||||||
|
|
||||||
|
.. warning::
|
||||||
|
|
||||||
|
Implicit conversion assumes that a returned ``char *`` is null-terminated.
|
||||||
|
If there is no null terminator a buffer overrun will occur.
|
||||||
|
|
||||||
|
Explicit conversions
|
||||||
|
--------------------
|
||||||
|
|
||||||
|
If some C++ code constructs a ``std::string`` that is not a UTF-8 string, one
|
||||||
|
can perform a explicit conversion and return a ``py::str`` object. Explicit
|
||||||
|
conversion has the same overhead as implicit conversion.
|
||||||
|
|
||||||
|
.. code-block:: c++
|
||||||
|
|
||||||
|
// This uses the Python C API to convert Latin-1 to Unicode
|
||||||
|
m.def("str_output",
|
||||||
|
[]() {
|
||||||
|
std::string s = "Send your r\xe9sum\xe9 to Alice in HR"; // Latin-1
|
||||||
|
py::str py_s = PyUnicode_DecodeLatin1(s.data(), s.length());
|
||||||
|
return py_s;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
>>> str_output()
|
||||||
|
'Send your résumé to Alice in HR'
|
||||||
|
|
||||||
|
The `Python C API
|
||||||
|
<https://docs.python.org/3/c-api/unicode.html#built-in-codecs>`_ provides
|
||||||
|
several built-in codecs.
|
||||||
|
|
||||||
|
|
||||||
|
One could also use a third party encoding library such as libiconv to transcode
|
||||||
|
to UTF-8.
|
||||||
|
|
||||||
|
Return C++ strings without conversion
|
||||||
|
-------------------------------------
|
||||||
|
|
||||||
|
If the data in a C++ ``std::string`` does not represent text and should be
|
||||||
|
returned to Python as ``bytes``, then one can return the data as a
|
||||||
|
``py::bytes`` object.
|
||||||
|
|
||||||
|
.. code-block:: c++
|
||||||
|
|
||||||
|
m.def("return_bytes",
|
||||||
|
[]() {
|
||||||
|
std::string s("\xba\xd0\xba\xd0"); // Not valid UTF-8
|
||||||
|
return py::bytes(s); // Return the data without transcoding
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
>>> example.return_bytes()
|
||||||
|
b'\xba\xd0\xba\xd0'
|
||||||
|
|
||||||
|
|
||||||
|
Note the asymmetry: pybind11 will convert ``bytes`` to ``std::string`` without
|
||||||
|
encoding, but cannot convert ``std::string`` back to ``bytes`` implicitly.
|
||||||
|
|
||||||
|
.. code-block:: c++
|
||||||
|
|
||||||
|
m.def("asymmetry",
|
||||||
|
[](std::string s) { // Accepts str or bytes from Python
|
||||||
|
return s; // Looks harmless, but implicitly converts to str
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
>>> isinstance(example.asymmetry(b"have some bytes"), str)
|
||||||
|
True
|
||||||
|
|
||||||
|
>>> example.asymmetry(b"\xba\xd0\xba\xd0") # invalid utf-8 as bytes
|
||||||
|
UnicodeDecodeError: 'utf-8' codec can't decode byte 0xba in position 0: invalid start byte
|
||||||
|
|
||||||
|
|
||||||
|
Wide character strings
|
||||||
|
======================
|
||||||
|
|
||||||
|
When a Python ``str`` is passed to a C++ function expecting ``std::wstring``,
|
||||||
|
``wchar_t*``, ``std::u16string`` or ``std::u32string``, the ``str`` will be
|
||||||
|
encoded to UTF-16 or UTF-32 depending on how the C++ compiler implements each
|
||||||
|
type, in the platform's native endianness. When strings of these types are
|
||||||
|
returned, they are assumed to contain valid UTF-16 or UTF-32, and will be
|
||||||
|
decoded to Python ``str``.
|
||||||
|
|
||||||
|
.. code-block:: c++
|
||||||
|
|
||||||
|
#define UNICODE
|
||||||
|
#include <windows.h>
|
||||||
|
|
||||||
|
m.def("set_window_text",
|
||||||
|
[](HWND hwnd, std::wstring s) {
|
||||||
|
// Call SetWindowText with null-terminated UTF-16 string
|
||||||
|
::SetWindowText(hwnd, s.c_str());
|
||||||
|
}
|
||||||
|
);
|
||||||
|
m.def("get_window_text",
|
||||||
|
[](HWND hwnd) {
|
||||||
|
const int buffer_size = ::GetWindowTextLength(hwnd) + 1;
|
||||||
|
auto buffer = std::make_unique< wchar_t[] >(buffer_size);
|
||||||
|
|
||||||
|
::GetWindowText(hwnd, buffer.data(), buffer_size);
|
||||||
|
|
||||||
|
std::wstring text(buffer.get());
|
||||||
|
|
||||||
|
// wstring will be converted to Python str
|
||||||
|
return text;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
.. warning::
|
||||||
|
|
||||||
|
Wide character strings may not work as described on Python 2.7 or Python
|
||||||
|
3.3 compiled with ``--enable-unicode=ucs2``.
|
||||||
|
|
||||||
|
Strings in multibyte encodings such as Shift-JIS must transcoded to a
|
||||||
|
UTF-8/16/32 before being returned to Python.
|
||||||
|
|
||||||
|
|
||||||
|
Character literals
|
||||||
|
==================
|
||||||
|
|
||||||
|
C++ functions that accept character literals as input will receive the first
|
||||||
|
character of a Python ``str`` as their input. If the string is longer than one
|
||||||
|
Unicode character, trailing characters will be ignored.
|
||||||
|
|
||||||
|
When a character literal is returned from C++ (such as a ``char`` or a
|
||||||
|
``wchar_t``), it will be converted to a ``str`` that represents the single
|
||||||
|
character.
|
||||||
|
|
||||||
|
.. code-block:: c++
|
||||||
|
|
||||||
|
m.def("pass_char", [](char c) { return c; });
|
||||||
|
m.def("pass_wchar", [](wchar_t w) { return w; });
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
>>> example.pass_char('A')
|
||||||
|
'A'
|
||||||
|
|
||||||
|
While C++ will cast integers to character types (``char c = 0x65;``), pybind11
|
||||||
|
does not convert Python integers to characters implicitly. The Python function
|
||||||
|
``chr()`` can be used to convert integers to characters.
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
>>> example.pass_char(0x65)
|
||||||
|
TypeError
|
||||||
|
|
||||||
|
>>> example.pass_char(chr(0x65))
|
||||||
|
'A'
|
||||||
|
|
||||||
|
If the desire is to work with an 8-bit integer, use ``int8_t`` or ``uint8_t``
|
||||||
|
as the argument type.
|
||||||
|
|
||||||
|
Grapheme clusters
|
||||||
|
-----------------
|
||||||
|
|
||||||
|
A single grapheme may be represented by two or more Unicode characters. For
|
||||||
|
example 'é' is usually represented as U+00E9 but can also be expressed as the
|
||||||
|
combining character sequence U+0065 U+0301 (that is, the letter 'e' followed by
|
||||||
|
a combining acute accent). The combining character will be lost if the
|
||||||
|
two-character sequence is passed as an argument, even though it renders as a
|
||||||
|
single grapheme.
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
>>> example.pass_wchar('é')
|
||||||
|
'é'
|
||||||
|
|
||||||
|
>>> combining_e_acute = 'e' + '\u0301'
|
||||||
|
|
||||||
|
>>> combining_e_acute
|
||||||
|
'é'
|
||||||
|
|
||||||
|
>>> combining_e_acute == 'é'
|
||||||
|
False
|
||||||
|
|
||||||
|
>>> example.pass_wchar(combining_e_acute)
|
||||||
|
'e'
|
||||||
|
|
||||||
|
Normalizing combining characters before passing the character literal to C++
|
||||||
|
may resolve *some* of these issues:
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
>>> example.pass_wchar(unicodedata.normalize('NFC', combining_e_acute))
|
||||||
|
'é'
|
||||||
|
|
||||||
|
In some languages (Thai for example), there are `graphemes that cannot be
|
||||||
|
expressed as a single Unicode code point
|
||||||
|
<http://unicode.org/reports/tr29/#Grapheme_Cluster_Boundaries>`_, so there is
|
||||||
|
no way to capture them in a C++ character type.
|
||||||
|
|
||||||
|
|
||||||
|
C++17 string views
|
||||||
|
==================
|
||||||
|
|
||||||
|
C++17 string views are automatically supported when compiling in C++17 mode.
|
||||||
|
They follow the same rules for encoding and decoding as the corresponding STL
|
||||||
|
string type (for example, a ``std::u16string_view`` argument will be passed
|
||||||
|
UTF-16-encoded data, and a returned ``std::string_view`` will be decoded as
|
||||||
|
UTF-8).
|
||||||
|
|
||||||
|
References
|
||||||
|
==========
|
||||||
|
|
||||||
|
* `The Absolute Minimum Every Software Developer Absolutely, Positively Must Know About Unicode and Character Sets (No Excuses!) <https://www.joelonsoftware.com/2003/10/08/the-absolute-minimum-every-software-developer-absolutely-positively-must-know-about-unicode-and-character-sets-no-excuses/>`_
|
||||||
|
* `C++ - Using STL Strings at Win32 API Boundaries <https://msdn.microsoft.com/en-ca/magazine/mt238407.aspx>`_
|
1126
3rdparty/pybind11/docs/advanced/classes.rst
vendored
Normal file
1126
3rdparty/pybind11/docs/advanced/classes.rst
vendored
Normal file
File diff suppressed because it is too large
Load Diff
261
3rdparty/pybind11/docs/advanced/embedding.rst
vendored
Normal file
261
3rdparty/pybind11/docs/advanced/embedding.rst
vendored
Normal file
@ -0,0 +1,261 @@
|
|||||||
|
.. _embedding:
|
||||||
|
|
||||||
|
Embedding the interpreter
|
||||||
|
#########################
|
||||||
|
|
||||||
|
While pybind11 is mainly focused on extending Python using C++, it's also
|
||||||
|
possible to do the reverse: embed the Python interpreter into a C++ program.
|
||||||
|
All of the other documentation pages still apply here, so refer to them for
|
||||||
|
general pybind11 usage. This section will cover a few extra things required
|
||||||
|
for embedding.
|
||||||
|
|
||||||
|
Getting started
|
||||||
|
===============
|
||||||
|
|
||||||
|
A basic executable with an embedded interpreter can be created with just a few
|
||||||
|
lines of CMake and the ``pybind11::embed`` target, as shown below. For more
|
||||||
|
information, see :doc:`/compiling`.
|
||||||
|
|
||||||
|
.. code-block:: cmake
|
||||||
|
|
||||||
|
cmake_minimum_required(VERSION 3.0)
|
||||||
|
project(example)
|
||||||
|
|
||||||
|
find_package(pybind11 REQUIRED) # or `add_subdirectory(pybind11)`
|
||||||
|
|
||||||
|
add_executable(example main.cpp)
|
||||||
|
target_link_libraries(example PRIVATE pybind11::embed)
|
||||||
|
|
||||||
|
The essential structure of the ``main.cpp`` file looks like this:
|
||||||
|
|
||||||
|
.. code-block:: cpp
|
||||||
|
|
||||||
|
#include <pybind11/embed.h> // everything needed for embedding
|
||||||
|
namespace py = pybind11;
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
py::scoped_interpreter guard{}; // start the interpreter and keep it alive
|
||||||
|
|
||||||
|
py::print("Hello, World!"); // use the Python API
|
||||||
|
}
|
||||||
|
|
||||||
|
The interpreter must be initialized before using any Python API, which includes
|
||||||
|
all the functions and classes in pybind11. The RAII guard class `scoped_interpreter`
|
||||||
|
takes care of the interpreter lifetime. After the guard is destroyed, the interpreter
|
||||||
|
shuts down and clears its memory. No Python functions can be called after this.
|
||||||
|
|
||||||
|
Executing Python code
|
||||||
|
=====================
|
||||||
|
|
||||||
|
There are a few different ways to run Python code. One option is to use `eval`,
|
||||||
|
`exec` or `eval_file`, as explained in :ref:`eval`. Here is a quick example in
|
||||||
|
the context of an executable with an embedded interpreter:
|
||||||
|
|
||||||
|
.. code-block:: cpp
|
||||||
|
|
||||||
|
#include <pybind11/embed.h>
|
||||||
|
namespace py = pybind11;
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
py::scoped_interpreter guard{};
|
||||||
|
|
||||||
|
py::exec(R"(
|
||||||
|
kwargs = dict(name="World", number=42)
|
||||||
|
message = "Hello, {name}! The answer is {number}".format(**kwargs)
|
||||||
|
print(message)
|
||||||
|
)");
|
||||||
|
}
|
||||||
|
|
||||||
|
Alternatively, similar results can be achieved using pybind11's API (see
|
||||||
|
:doc:`/advanced/pycpp/index` for more details).
|
||||||
|
|
||||||
|
.. code-block:: cpp
|
||||||
|
|
||||||
|
#include <pybind11/embed.h>
|
||||||
|
namespace py = pybind11;
|
||||||
|
using namespace py::literals;
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
py::scoped_interpreter guard{};
|
||||||
|
|
||||||
|
auto kwargs = py::dict("name"_a="World", "number"_a=42);
|
||||||
|
auto message = "Hello, {name}! The answer is {number}"_s.format(**kwargs);
|
||||||
|
py::print(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
The two approaches can also be combined:
|
||||||
|
|
||||||
|
.. code-block:: cpp
|
||||||
|
|
||||||
|
#include <pybind11/embed.h>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
namespace py = pybind11;
|
||||||
|
using namespace py::literals;
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
py::scoped_interpreter guard{};
|
||||||
|
|
||||||
|
auto locals = py::dict("name"_a="World", "number"_a=42);
|
||||||
|
py::exec(R"(
|
||||||
|
message = "Hello, {name}! The answer is {number}".format(**locals())
|
||||||
|
)", py::globals(), locals);
|
||||||
|
|
||||||
|
auto message = locals["message"].cast<std::string>();
|
||||||
|
std::cout << message;
|
||||||
|
}
|
||||||
|
|
||||||
|
Importing modules
|
||||||
|
=================
|
||||||
|
|
||||||
|
Python modules can be imported using `module::import()`:
|
||||||
|
|
||||||
|
.. code-block:: cpp
|
||||||
|
|
||||||
|
py::module sys = py::module::import("sys");
|
||||||
|
py::print(sys.attr("path"));
|
||||||
|
|
||||||
|
For convenience, the current working directory is included in ``sys.path`` when
|
||||||
|
embedding the interpreter. This makes it easy to import local Python files:
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
"""calc.py located in the working directory"""
|
||||||
|
|
||||||
|
def add(i, j):
|
||||||
|
return i + j
|
||||||
|
|
||||||
|
|
||||||
|
.. code-block:: cpp
|
||||||
|
|
||||||
|
py::module calc = py::module::import("calc");
|
||||||
|
py::object result = calc.attr("add")(1, 2);
|
||||||
|
int n = result.cast<int>();
|
||||||
|
assert(n == 3);
|
||||||
|
|
||||||
|
Modules can be reloaded using `module::reload()` if the source is modified e.g.
|
||||||
|
by an external process. This can be useful in scenarios where the application
|
||||||
|
imports a user defined data processing script which needs to be updated after
|
||||||
|
changes by the user. Note that this function does not reload modules recursively.
|
||||||
|
|
||||||
|
.. _embedding_modules:
|
||||||
|
|
||||||
|
Adding embedded modules
|
||||||
|
=======================
|
||||||
|
|
||||||
|
Embedded binary modules can be added using the `PYBIND11_EMBEDDED_MODULE` macro.
|
||||||
|
Note that the definition must be placed at global scope. They can be imported
|
||||||
|
like any other module.
|
||||||
|
|
||||||
|
.. code-block:: cpp
|
||||||
|
|
||||||
|
#include <pybind11/embed.h>
|
||||||
|
namespace py = pybind11;
|
||||||
|
|
||||||
|
PYBIND11_EMBEDDED_MODULE(fast_calc, m) {
|
||||||
|
// `m` is a `py::module` which is used to bind functions and classes
|
||||||
|
m.def("add", [](int i, int j) {
|
||||||
|
return i + j;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
py::scoped_interpreter guard{};
|
||||||
|
|
||||||
|
auto fast_calc = py::module::import("fast_calc");
|
||||||
|
auto result = fast_calc.attr("add")(1, 2).cast<int>();
|
||||||
|
assert(result == 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
Unlike extension modules where only a single binary module can be created, on
|
||||||
|
the embedded side an unlimited number of modules can be added using multiple
|
||||||
|
`PYBIND11_EMBEDDED_MODULE` definitions (as long as they have unique names).
|
||||||
|
|
||||||
|
These modules are added to Python's list of builtins, so they can also be
|
||||||
|
imported in pure Python files loaded by the interpreter. Everything interacts
|
||||||
|
naturally:
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
"""py_module.py located in the working directory"""
|
||||||
|
import cpp_module
|
||||||
|
|
||||||
|
a = cpp_module.a
|
||||||
|
b = a + 1
|
||||||
|
|
||||||
|
|
||||||
|
.. code-block:: cpp
|
||||||
|
|
||||||
|
#include <pybind11/embed.h>
|
||||||
|
namespace py = pybind11;
|
||||||
|
|
||||||
|
PYBIND11_EMBEDDED_MODULE(cpp_module, m) {
|
||||||
|
m.attr("a") = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
py::scoped_interpreter guard{};
|
||||||
|
|
||||||
|
auto py_module = py::module::import("py_module");
|
||||||
|
|
||||||
|
auto locals = py::dict("fmt"_a="{} + {} = {}", **py_module.attr("__dict__"));
|
||||||
|
assert(locals["a"].cast<int>() == 1);
|
||||||
|
assert(locals["b"].cast<int>() == 2);
|
||||||
|
|
||||||
|
py::exec(R"(
|
||||||
|
c = a + b
|
||||||
|
message = fmt.format(a, b, c)
|
||||||
|
)", py::globals(), locals);
|
||||||
|
|
||||||
|
assert(locals["c"].cast<int>() == 3);
|
||||||
|
assert(locals["message"].cast<std::string>() == "1 + 2 = 3");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Interpreter lifetime
|
||||||
|
====================
|
||||||
|
|
||||||
|
The Python interpreter shuts down when `scoped_interpreter` is destroyed. After
|
||||||
|
this, creating a new instance will restart the interpreter. Alternatively, the
|
||||||
|
`initialize_interpreter` / `finalize_interpreter` pair of functions can be used
|
||||||
|
to directly set the state at any time.
|
||||||
|
|
||||||
|
Modules created with pybind11 can be safely re-initialized after the interpreter
|
||||||
|
has been restarted. However, this may not apply to third-party extension modules.
|
||||||
|
The issue is that Python itself cannot completely unload extension modules and
|
||||||
|
there are several caveats with regard to interpreter restarting. In short, not
|
||||||
|
all memory may be freed, either due to Python reference cycles or user-created
|
||||||
|
global data. All the details can be found in the CPython documentation.
|
||||||
|
|
||||||
|
.. warning::
|
||||||
|
|
||||||
|
Creating two concurrent `scoped_interpreter` guards is a fatal error. So is
|
||||||
|
calling `initialize_interpreter` for a second time after the interpreter
|
||||||
|
has already been initialized.
|
||||||
|
|
||||||
|
Do not use the raw CPython API functions ``Py_Initialize`` and
|
||||||
|
``Py_Finalize`` as these do not properly handle the lifetime of
|
||||||
|
pybind11's internal data.
|
||||||
|
|
||||||
|
|
||||||
|
Sub-interpreter support
|
||||||
|
=======================
|
||||||
|
|
||||||
|
Creating multiple copies of `scoped_interpreter` is not possible because it
|
||||||
|
represents the main Python interpreter. Sub-interpreters are something different
|
||||||
|
and they do permit the existence of multiple interpreters. This is an advanced
|
||||||
|
feature of the CPython API and should be handled with care. pybind11 does not
|
||||||
|
currently offer a C++ interface for sub-interpreters, so refer to the CPython
|
||||||
|
documentation for all the details regarding this feature.
|
||||||
|
|
||||||
|
We'll just mention a couple of caveats the sub-interpreters support in pybind11:
|
||||||
|
|
||||||
|
1. Sub-interpreters will not receive independent copies of embedded modules.
|
||||||
|
Instead, these are shared and modifications in one interpreter may be
|
||||||
|
reflected in another.
|
||||||
|
|
||||||
|
2. Managing multiple threads, multiple interpreters and the GIL can be
|
||||||
|
challenging and there are several caveats here, even within the pure
|
||||||
|
CPython API (please refer to the Python docs for details). As for
|
||||||
|
pybind11, keep in mind that `gil_scoped_release` and `gil_scoped_acquire`
|
||||||
|
do not take sub-interpreters into account.
|
144
3rdparty/pybind11/docs/advanced/exceptions.rst
vendored
Normal file
144
3rdparty/pybind11/docs/advanced/exceptions.rst
vendored
Normal file
@ -0,0 +1,144 @@
|
|||||||
|
Exceptions
|
||||||
|
##########
|
||||||
|
|
||||||
|
Built-in exception translation
|
||||||
|
==============================
|
||||||
|
|
||||||
|
When C++ code invoked from Python throws an ``std::exception``, it is
|
||||||
|
automatically converted into a Python ``Exception``. pybind11 defines multiple
|
||||||
|
special exception classes that will map to different types of Python
|
||||||
|
exceptions:
|
||||||
|
|
||||||
|
.. tabularcolumns:: |p{0.5\textwidth}|p{0.45\textwidth}|
|
||||||
|
|
||||||
|
+--------------------------------------+--------------------------------------+
|
||||||
|
| C++ exception type | Python exception type |
|
||||||
|
+======================================+======================================+
|
||||||
|
| :class:`std::exception` | ``RuntimeError`` |
|
||||||
|
+--------------------------------------+--------------------------------------+
|
||||||
|
| :class:`std::bad_alloc` | ``MemoryError`` |
|
||||||
|
+--------------------------------------+--------------------------------------+
|
||||||
|
| :class:`std::domain_error` | ``ValueError`` |
|
||||||
|
+--------------------------------------+--------------------------------------+
|
||||||
|
| :class:`std::invalid_argument` | ``ValueError`` |
|
||||||
|
+--------------------------------------+--------------------------------------+
|
||||||
|
| :class:`std::length_error` | ``ValueError`` |
|
||||||
|
+--------------------------------------+--------------------------------------+
|
||||||
|
| :class:`std::out_of_range` | ``IndexError`` |
|
||||||
|
+--------------------------------------+--------------------------------------+
|
||||||
|
| :class:`std::range_error` | ``ValueError`` |
|
||||||
|
+--------------------------------------+--------------------------------------+
|
||||||
|
| :class:`std::overflow_error` | ``OverflowError`` |
|
||||||
|
+--------------------------------------+--------------------------------------+
|
||||||
|
| :class:`pybind11::stop_iteration` | ``StopIteration`` (used to implement |
|
||||||
|
| | custom iterators) |
|
||||||
|
+--------------------------------------+--------------------------------------+
|
||||||
|
| :class:`pybind11::index_error` | ``IndexError`` (used to indicate out |
|
||||||
|
| | of bounds access in ``__getitem__``, |
|
||||||
|
| | ``__setitem__``, etc.) |
|
||||||
|
+--------------------------------------+--------------------------------------+
|
||||||
|
| :class:`pybind11::value_error` | ``ValueError`` (used to indicate |
|
||||||
|
| | wrong value passed in |
|
||||||
|
| | ``container.remove(...)``) |
|
||||||
|
+--------------------------------------+--------------------------------------+
|
||||||
|
| :class:`pybind11::key_error` | ``KeyError`` (used to indicate out |
|
||||||
|
| | of bounds access in ``__getitem__``, |
|
||||||
|
| | ``__setitem__`` in dict-like |
|
||||||
|
| | objects, etc.) |
|
||||||
|
+--------------------------------------+--------------------------------------+
|
||||||
|
| :class:`pybind11::error_already_set` | Indicates that the Python exception |
|
||||||
|
| | flag has already been set via Python |
|
||||||
|
| | API calls from C++ code; this C++ |
|
||||||
|
| | exception is used to propagate such |
|
||||||
|
| | a Python exception back to Python. |
|
||||||
|
+--------------------------------------+--------------------------------------+
|
||||||
|
|
||||||
|
When a Python function invoked from C++ throws an exception, it is converted
|
||||||
|
into a C++ exception of type :class:`error_already_set` whose string payload
|
||||||
|
contains a textual summary.
|
||||||
|
|
||||||
|
There is also a special exception :class:`cast_error` that is thrown by
|
||||||
|
:func:`handle::call` when the input arguments cannot be converted to Python
|
||||||
|
objects.
|
||||||
|
|
||||||
|
Registering custom translators
|
||||||
|
==============================
|
||||||
|
|
||||||
|
If the default exception conversion policy described above is insufficient,
|
||||||
|
pybind11 also provides support for registering custom exception translators.
|
||||||
|
To register a simple exception conversion that translates a C++ exception into
|
||||||
|
a new Python exception using the C++ exception's ``what()`` method, a helper
|
||||||
|
function is available:
|
||||||
|
|
||||||
|
.. code-block:: cpp
|
||||||
|
|
||||||
|
py::register_exception<CppExp>(module, "PyExp");
|
||||||
|
|
||||||
|
This call creates a Python exception class with the name ``PyExp`` in the given
|
||||||
|
module and automatically converts any encountered exceptions of type ``CppExp``
|
||||||
|
into Python exceptions of type ``PyExp``.
|
||||||
|
|
||||||
|
When more advanced exception translation is needed, the function
|
||||||
|
``py::register_exception_translator(translator)`` can be used to register
|
||||||
|
functions that can translate arbitrary exception types (and which may include
|
||||||
|
additional logic to do so). The function takes a stateless callable (e.g. a
|
||||||
|
function pointer or a lambda function without captured variables) with the call
|
||||||
|
signature ``void(std::exception_ptr)``.
|
||||||
|
|
||||||
|
When a C++ exception is thrown, the registered exception translators are tried
|
||||||
|
in reverse order of registration (i.e. the last registered translator gets the
|
||||||
|
first shot at handling the exception).
|
||||||
|
|
||||||
|
Inside the translator, ``std::rethrow_exception`` should be used within
|
||||||
|
a try block to re-throw the exception. One or more catch clauses to catch
|
||||||
|
the appropriate exceptions should then be used with each clause using
|
||||||
|
``PyErr_SetString`` to set a Python exception or ``ex(string)`` to set
|
||||||
|
the python exception to a custom exception type (see below).
|
||||||
|
|
||||||
|
To declare a custom Python exception type, declare a ``py::exception`` variable
|
||||||
|
and use this in the associated exception translator (note: it is often useful
|
||||||
|
to make this a static declaration when using it inside a lambda expression
|
||||||
|
without requiring capturing).
|
||||||
|
|
||||||
|
|
||||||
|
The following example demonstrates this for a hypothetical exception classes
|
||||||
|
``MyCustomException`` and ``OtherException``: the first is translated to a
|
||||||
|
custom python exception ``MyCustomError``, while the second is translated to a
|
||||||
|
standard python RuntimeError:
|
||||||
|
|
||||||
|
.. code-block:: cpp
|
||||||
|
|
||||||
|
static py::exception<MyCustomException> exc(m, "MyCustomError");
|
||||||
|
py::register_exception_translator([](std::exception_ptr p) {
|
||||||
|
try {
|
||||||
|
if (p) std::rethrow_exception(p);
|
||||||
|
} catch (const MyCustomException &e) {
|
||||||
|
exc(e.what());
|
||||||
|
} catch (const OtherException &e) {
|
||||||
|
PyErr_SetString(PyExc_RuntimeError, e.what());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Multiple exceptions can be handled by a single translator, as shown in the
|
||||||
|
example above. If the exception is not caught by the current translator, the
|
||||||
|
previously registered one gets a chance.
|
||||||
|
|
||||||
|
If none of the registered exception translators is able to handle the
|
||||||
|
exception, it is handled by the default converter as described in the previous
|
||||||
|
section.
|
||||||
|
|
||||||
|
.. seealso::
|
||||||
|
|
||||||
|
The file :file:`tests/test_exceptions.cpp` contains examples
|
||||||
|
of various custom exception translators and custom exception types.
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
|
||||||
|
You must call either ``PyErr_SetString`` or a custom exception's call
|
||||||
|
operator (``exc(string)``) for every exception caught in a custom exception
|
||||||
|
translator. Failure to do so will cause Python to crash with ``SystemError:
|
||||||
|
error return without exception set``.
|
||||||
|
|
||||||
|
Exceptions that you do not plan to handle should simply not be caught, or
|
||||||
|
may be explicitly (re-)thrown to delegate it to the other,
|
||||||
|
previously-declared existing exception translators.
|
507
3rdparty/pybind11/docs/advanced/functions.rst
vendored
Normal file
507
3rdparty/pybind11/docs/advanced/functions.rst
vendored
Normal file
@ -0,0 +1,507 @@
|
|||||||
|
Functions
|
||||||
|
#########
|
||||||
|
|
||||||
|
Before proceeding with this section, make sure that you are already familiar
|
||||||
|
with the basics of binding functions and classes, as explained in :doc:`/basics`
|
||||||
|
and :doc:`/classes`. The following guide is applicable to both free and member
|
||||||
|
functions, i.e. *methods* in Python.
|
||||||
|
|
||||||
|
.. _return_value_policies:
|
||||||
|
|
||||||
|
Return value policies
|
||||||
|
=====================
|
||||||
|
|
||||||
|
Python and C++ use fundamentally different ways of managing the memory and
|
||||||
|
lifetime of objects managed by them. This can lead to issues when creating
|
||||||
|
bindings for functions that return a non-trivial type. Just by looking at the
|
||||||
|
type information, it is not clear whether Python should take charge of the
|
||||||
|
returned value and eventually free its resources, or if this is handled on the
|
||||||
|
C++ side. For this reason, pybind11 provides a several *return value policy*
|
||||||
|
annotations that can be passed to the :func:`module::def` and
|
||||||
|
:func:`class_::def` functions. The default policy is
|
||||||
|
:enum:`return_value_policy::automatic`.
|
||||||
|
|
||||||
|
Return value policies are tricky, and it's very important to get them right.
|
||||||
|
Just to illustrate what can go wrong, consider the following simple example:
|
||||||
|
|
||||||
|
.. code-block:: cpp
|
||||||
|
|
||||||
|
/* Function declaration */
|
||||||
|
Data *get_data() { return _data; /* (pointer to a static data structure) */ }
|
||||||
|
...
|
||||||
|
|
||||||
|
/* Binding code */
|
||||||
|
m.def("get_data", &get_data); // <-- KABOOM, will cause crash when called from Python
|
||||||
|
|
||||||
|
What's going on here? When ``get_data()`` is called from Python, the return
|
||||||
|
value (a native C++ type) must be wrapped to turn it into a usable Python type.
|
||||||
|
In this case, the default return value policy (:enum:`return_value_policy::automatic`)
|
||||||
|
causes pybind11 to assume ownership of the static ``_data`` instance.
|
||||||
|
|
||||||
|
When Python's garbage collector eventually deletes the Python
|
||||||
|
wrapper, pybind11 will also attempt to delete the C++ instance (via ``operator
|
||||||
|
delete()``) due to the implied ownership. At this point, the entire application
|
||||||
|
will come crashing down, though errors could also be more subtle and involve
|
||||||
|
silent data corruption.
|
||||||
|
|
||||||
|
In the above example, the policy :enum:`return_value_policy::reference` should have
|
||||||
|
been specified so that the global data instance is only *referenced* without any
|
||||||
|
implied transfer of ownership, i.e.:
|
||||||
|
|
||||||
|
.. code-block:: cpp
|
||||||
|
|
||||||
|
m.def("get_data", &get_data, return_value_policy::reference);
|
||||||
|
|
||||||
|
On the other hand, this is not the right policy for many other situations,
|
||||||
|
where ignoring ownership could lead to resource leaks.
|
||||||
|
As a developer using pybind11, it's important to be familiar with the different
|
||||||
|
return value policies, including which situation calls for which one of them.
|
||||||
|
The following table provides an overview of available policies:
|
||||||
|
|
||||||
|
.. tabularcolumns:: |p{0.5\textwidth}|p{0.45\textwidth}|
|
||||||
|
|
||||||
|
+--------------------------------------------------+----------------------------------------------------------------------------+
|
||||||
|
| Return value policy | Description |
|
||||||
|
+==================================================+============================================================================+
|
||||||
|
| :enum:`return_value_policy::take_ownership` | Reference an existing object (i.e. do not create a new copy) and take |
|
||||||
|
| | ownership. Python will call the destructor and delete operator when the |
|
||||||
|
| | object's reference count reaches zero. Undefined behavior ensues when the |
|
||||||
|
| | C++ side does the same, or when the data was not dynamically allocated. |
|
||||||
|
+--------------------------------------------------+----------------------------------------------------------------------------+
|
||||||
|
| :enum:`return_value_policy::copy` | Create a new copy of the returned object, which will be owned by Python. |
|
||||||
|
| | This policy is comparably safe because the lifetimes of the two instances |
|
||||||
|
| | are decoupled. |
|
||||||
|
+--------------------------------------------------+----------------------------------------------------------------------------+
|
||||||
|
| :enum:`return_value_policy::move` | Use ``std::move`` to move the return value contents into a new instance |
|
||||||
|
| | that will be owned by Python. This policy is comparably safe because the |
|
||||||
|
| | lifetimes of the two instances (move source and destination) are decoupled.|
|
||||||
|
+--------------------------------------------------+----------------------------------------------------------------------------+
|
||||||
|
| :enum:`return_value_policy::reference` | Reference an existing object, but do not take ownership. The C++ side is |
|
||||||
|
| | responsible for managing the object's lifetime and deallocating it when |
|
||||||
|
| | it is no longer used. Warning: undefined behavior will ensue when the C++ |
|
||||||
|
| | side deletes an object that is still referenced and used by Python. |
|
||||||
|
+--------------------------------------------------+----------------------------------------------------------------------------+
|
||||||
|
| :enum:`return_value_policy::reference_internal` | Indicates that the lifetime of the return value is tied to the lifetime |
|
||||||
|
| | of a parent object, namely the implicit ``this``, or ``self`` argument of |
|
||||||
|
| | the called method or property. Internally, this policy works just like |
|
||||||
|
| | :enum:`return_value_policy::reference` but additionally applies a |
|
||||||
|
| | ``keep_alive<0, 1>`` *call policy* (described in the next section) that |
|
||||||
|
| | prevents the parent object from being garbage collected as long as the |
|
||||||
|
| | return value is referenced by Python. This is the default policy for |
|
||||||
|
| | property getters created via ``def_property``, ``def_readwrite``, etc. |
|
||||||
|
+--------------------------------------------------+----------------------------------------------------------------------------+
|
||||||
|
| :enum:`return_value_policy::automatic` | **Default policy.** This policy falls back to the policy |
|
||||||
|
| | :enum:`return_value_policy::take_ownership` when the return value is a |
|
||||||
|
| | pointer. Otherwise, it uses :enum:`return_value_policy::move` or |
|
||||||
|
| | :enum:`return_value_policy::copy` for rvalue and lvalue references, |
|
||||||
|
| | respectively. See above for a description of what all of these different |
|
||||||
|
| | policies do. |
|
||||||
|
+--------------------------------------------------+----------------------------------------------------------------------------+
|
||||||
|
| :enum:`return_value_policy::automatic_reference` | As above, but use policy :enum:`return_value_policy::reference` when the |
|
||||||
|
| | return value is a pointer. This is the default conversion policy for |
|
||||||
|
| | function arguments when calling Python functions manually from C++ code |
|
||||||
|
| | (i.e. via handle::operator()). You probably won't need to use this. |
|
||||||
|
+--------------------------------------------------+----------------------------------------------------------------------------+
|
||||||
|
|
||||||
|
Return value policies can also be applied to properties:
|
||||||
|
|
||||||
|
.. code-block:: cpp
|
||||||
|
|
||||||
|
class_<MyClass>(m, "MyClass")
|
||||||
|
.def_property("data", &MyClass::getData, &MyClass::setData,
|
||||||
|
py::return_value_policy::copy);
|
||||||
|
|
||||||
|
Technically, the code above applies the policy to both the getter and the
|
||||||
|
setter function, however, the setter doesn't really care about *return*
|
||||||
|
value policies which makes this a convenient terse syntax. Alternatively,
|
||||||
|
targeted arguments can be passed through the :class:`cpp_function` constructor:
|
||||||
|
|
||||||
|
.. code-block:: cpp
|
||||||
|
|
||||||
|
class_<MyClass>(m, "MyClass")
|
||||||
|
.def_property("data"
|
||||||
|
py::cpp_function(&MyClass::getData, py::return_value_policy::copy),
|
||||||
|
py::cpp_function(&MyClass::setData)
|
||||||
|
);
|
||||||
|
|
||||||
|
.. warning::
|
||||||
|
|
||||||
|
Code with invalid return value policies might access uninitialized memory or
|
||||||
|
free data structures multiple times, which can lead to hard-to-debug
|
||||||
|
non-determinism and segmentation faults, hence it is worth spending the
|
||||||
|
time to understand all the different options in the table above.
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
|
||||||
|
One important aspect of the above policies is that they only apply to
|
||||||
|
instances which pybind11 has *not* seen before, in which case the policy
|
||||||
|
clarifies essential questions about the return value's lifetime and
|
||||||
|
ownership. When pybind11 knows the instance already (as identified by its
|
||||||
|
type and address in memory), it will return the existing Python object
|
||||||
|
wrapper rather than creating a new copy.
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
|
||||||
|
The next section on :ref:`call_policies` discusses *call policies* that can be
|
||||||
|
specified *in addition* to a return value policy from the list above. Call
|
||||||
|
policies indicate reference relationships that can involve both return values
|
||||||
|
and parameters of functions.
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
|
||||||
|
As an alternative to elaborate call policies and lifetime management logic,
|
||||||
|
consider using smart pointers (see the section on :ref:`smart_pointers` for
|
||||||
|
details). Smart pointers can tell whether an object is still referenced from
|
||||||
|
C++ or Python, which generally eliminates the kinds of inconsistencies that
|
||||||
|
can lead to crashes or undefined behavior. For functions returning smart
|
||||||
|
pointers, it is not necessary to specify a return value policy.
|
||||||
|
|
||||||
|
.. _call_policies:
|
||||||
|
|
||||||
|
Additional call policies
|
||||||
|
========================
|
||||||
|
|
||||||
|
In addition to the above return value policies, further *call policies* can be
|
||||||
|
specified to indicate dependencies between parameters or ensure a certain state
|
||||||
|
for the function call.
|
||||||
|
|
||||||
|
Keep alive
|
||||||
|
----------
|
||||||
|
|
||||||
|
In general, this policy is required when the C++ object is any kind of container
|
||||||
|
and another object is being added to the container. ``keep_alive<Nurse, Patient>``
|
||||||
|
indicates that the argument with index ``Patient`` should be kept alive at least
|
||||||
|
until the argument with index ``Nurse`` is freed by the garbage collector. Argument
|
||||||
|
indices start at one, while zero refers to the return value. For methods, index
|
||||||
|
``1`` refers to the implicit ``this`` pointer, while regular arguments begin at
|
||||||
|
index ``2``. Arbitrarily many call policies can be specified. When a ``Nurse``
|
||||||
|
with value ``None`` is detected at runtime, the call policy does nothing.
|
||||||
|
|
||||||
|
When the nurse is not a pybind11-registered type, the implementation internally
|
||||||
|
relies on the ability to create a *weak reference* to the nurse object. When
|
||||||
|
the nurse object is not a pybind11-registered type and does not support weak
|
||||||
|
references, an exception will be thrown.
|
||||||
|
|
||||||
|
Consider the following example: here, the binding code for a list append
|
||||||
|
operation ties the lifetime of the newly added element to the underlying
|
||||||
|
container:
|
||||||
|
|
||||||
|
.. code-block:: cpp
|
||||||
|
|
||||||
|
py::class_<List>(m, "List")
|
||||||
|
.def("append", &List::append, py::keep_alive<1, 2>());
|
||||||
|
|
||||||
|
For consistency, the argument indexing is identical for constructors. Index
|
||||||
|
``1`` still refers to the implicit ``this`` pointer, i.e. the object which is
|
||||||
|
being constructed. Index ``0`` refers to the return type which is presumed to
|
||||||
|
be ``void`` when a constructor is viewed like a function. The following example
|
||||||
|
ties the lifetime of the constructor element to the constructed object:
|
||||||
|
|
||||||
|
.. code-block:: cpp
|
||||||
|
|
||||||
|
py::class_<Nurse>(m, "Nurse")
|
||||||
|
.def(py::init<Patient &>(), py::keep_alive<1, 2>());
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
|
||||||
|
``keep_alive`` is analogous to the ``with_custodian_and_ward`` (if Nurse,
|
||||||
|
Patient != 0) and ``with_custodian_and_ward_postcall`` (if Nurse/Patient ==
|
||||||
|
0) policies from Boost.Python.
|
||||||
|
|
||||||
|
Call guard
|
||||||
|
----------
|
||||||
|
|
||||||
|
The ``call_guard<T>`` policy allows any scope guard type ``T`` to be placed
|
||||||
|
around the function call. For example, this definition:
|
||||||
|
|
||||||
|
.. code-block:: cpp
|
||||||
|
|
||||||
|
m.def("foo", foo, py::call_guard<T>());
|
||||||
|
|
||||||
|
is equivalent to the following pseudocode:
|
||||||
|
|
||||||
|
.. code-block:: cpp
|
||||||
|
|
||||||
|
m.def("foo", [](args...) {
|
||||||
|
T scope_guard;
|
||||||
|
return foo(args...); // forwarded arguments
|
||||||
|
});
|
||||||
|
|
||||||
|
The only requirement is that ``T`` is default-constructible, but otherwise any
|
||||||
|
scope guard will work. This is very useful in combination with `gil_scoped_release`.
|
||||||
|
See :ref:`gil`.
|
||||||
|
|
||||||
|
Multiple guards can also be specified as ``py::call_guard<T1, T2, T3...>``. The
|
||||||
|
constructor order is left to right and destruction happens in reverse.
|
||||||
|
|
||||||
|
.. seealso::
|
||||||
|
|
||||||
|
The file :file:`tests/test_call_policies.cpp` contains a complete example
|
||||||
|
that demonstrates using `keep_alive` and `call_guard` in more detail.
|
||||||
|
|
||||||
|
.. _python_objects_as_args:
|
||||||
|
|
||||||
|
Python objects as arguments
|
||||||
|
===========================
|
||||||
|
|
||||||
|
pybind11 exposes all major Python types using thin C++ wrapper classes. These
|
||||||
|
wrapper classes can also be used as parameters of functions in bindings, which
|
||||||
|
makes it possible to directly work with native Python types on the C++ side.
|
||||||
|
For instance, the following statement iterates over a Python ``dict``:
|
||||||
|
|
||||||
|
.. code-block:: cpp
|
||||||
|
|
||||||
|
void print_dict(py::dict dict) {
|
||||||
|
/* Easily interact with Python types */
|
||||||
|
for (auto item : dict)
|
||||||
|
std::cout << "key=" << std::string(py::str(item.first)) << ", "
|
||||||
|
<< "value=" << std::string(py::str(item.second)) << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
It can be exported:
|
||||||
|
|
||||||
|
.. code-block:: cpp
|
||||||
|
|
||||||
|
m.def("print_dict", &print_dict);
|
||||||
|
|
||||||
|
And used in Python as usual:
|
||||||
|
|
||||||
|
.. code-block:: pycon
|
||||||
|
|
||||||
|
>>> print_dict({'foo': 123, 'bar': 'hello'})
|
||||||
|
key=foo, value=123
|
||||||
|
key=bar, value=hello
|
||||||
|
|
||||||
|
For more information on using Python objects in C++, see :doc:`/advanced/pycpp/index`.
|
||||||
|
|
||||||
|
Accepting \*args and \*\*kwargs
|
||||||
|
===============================
|
||||||
|
|
||||||
|
Python provides a useful mechanism to define functions that accept arbitrary
|
||||||
|
numbers of arguments and keyword arguments:
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
def generic(*args, **kwargs):
|
||||||
|
... # do something with args and kwargs
|
||||||
|
|
||||||
|
Such functions can also be created using pybind11:
|
||||||
|
|
||||||
|
.. code-block:: cpp
|
||||||
|
|
||||||
|
void generic(py::args args, py::kwargs kwargs) {
|
||||||
|
/// .. do something with args
|
||||||
|
if (kwargs)
|
||||||
|
/// .. do something with kwargs
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Binding code
|
||||||
|
m.def("generic", &generic);
|
||||||
|
|
||||||
|
The class ``py::args`` derives from ``py::tuple`` and ``py::kwargs`` derives
|
||||||
|
from ``py::dict``.
|
||||||
|
|
||||||
|
You may also use just one or the other, and may combine these with other
|
||||||
|
arguments as long as the ``py::args`` and ``py::kwargs`` arguments are the last
|
||||||
|
arguments accepted by the function.
|
||||||
|
|
||||||
|
Please refer to the other examples for details on how to iterate over these,
|
||||||
|
and on how to cast their entries into C++ objects. A demonstration is also
|
||||||
|
available in ``tests/test_kwargs_and_defaults.cpp``.
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
|
||||||
|
When combining \*args or \*\*kwargs with :ref:`keyword_args` you should
|
||||||
|
*not* include ``py::arg`` tags for the ``py::args`` and ``py::kwargs``
|
||||||
|
arguments.
|
||||||
|
|
||||||
|
Default arguments revisited
|
||||||
|
===========================
|
||||||
|
|
||||||
|
The section on :ref:`default_args` previously discussed basic usage of default
|
||||||
|
arguments using pybind11. One noteworthy aspect of their implementation is that
|
||||||
|
default arguments are converted to Python objects right at declaration time.
|
||||||
|
Consider the following example:
|
||||||
|
|
||||||
|
.. code-block:: cpp
|
||||||
|
|
||||||
|
py::class_<MyClass>("MyClass")
|
||||||
|
.def("myFunction", py::arg("arg") = SomeType(123));
|
||||||
|
|
||||||
|
In this case, pybind11 must already be set up to deal with values of the type
|
||||||
|
``SomeType`` (via a prior instantiation of ``py::class_<SomeType>``), or an
|
||||||
|
exception will be thrown.
|
||||||
|
|
||||||
|
Another aspect worth highlighting is that the "preview" of the default argument
|
||||||
|
in the function signature is generated using the object's ``__repr__`` method.
|
||||||
|
If not available, the signature may not be very helpful, e.g.:
|
||||||
|
|
||||||
|
.. code-block:: pycon
|
||||||
|
|
||||||
|
FUNCTIONS
|
||||||
|
...
|
||||||
|
| myFunction(...)
|
||||||
|
| Signature : (MyClass, arg : SomeType = <SomeType object at 0x101b7b080>) -> NoneType
|
||||||
|
...
|
||||||
|
|
||||||
|
The first way of addressing this is by defining ``SomeType.__repr__``.
|
||||||
|
Alternatively, it is possible to specify the human-readable preview of the
|
||||||
|
default argument manually using the ``arg_v`` notation:
|
||||||
|
|
||||||
|
.. code-block:: cpp
|
||||||
|
|
||||||
|
py::class_<MyClass>("MyClass")
|
||||||
|
.def("myFunction", py::arg_v("arg", SomeType(123), "SomeType(123)"));
|
||||||
|
|
||||||
|
Sometimes it may be necessary to pass a null pointer value as a default
|
||||||
|
argument. In this case, remember to cast it to the underlying type in question,
|
||||||
|
like so:
|
||||||
|
|
||||||
|
.. code-block:: cpp
|
||||||
|
|
||||||
|
py::class_<MyClass>("MyClass")
|
||||||
|
.def("myFunction", py::arg("arg") = (SomeType *) nullptr);
|
||||||
|
|
||||||
|
.. _nonconverting_arguments:
|
||||||
|
|
||||||
|
Non-converting arguments
|
||||||
|
========================
|
||||||
|
|
||||||
|
Certain argument types may support conversion from one type to another. Some
|
||||||
|
examples of conversions are:
|
||||||
|
|
||||||
|
* :ref:`implicit_conversions` declared using ``py::implicitly_convertible<A,B>()``
|
||||||
|
* Calling a method accepting a double with an integer argument
|
||||||
|
* Calling a ``std::complex<float>`` argument with a non-complex python type
|
||||||
|
(for example, with a float). (Requires the optional ``pybind11/complex.h``
|
||||||
|
header).
|
||||||
|
* Calling a function taking an Eigen matrix reference with a numpy array of the
|
||||||
|
wrong type or of an incompatible data layout. (Requires the optional
|
||||||
|
``pybind11/eigen.h`` header).
|
||||||
|
|
||||||
|
This behaviour is sometimes undesirable: the binding code may prefer to raise
|
||||||
|
an error rather than convert the argument. This behaviour can be obtained
|
||||||
|
through ``py::arg`` by calling the ``.noconvert()`` method of the ``py::arg``
|
||||||
|
object, such as:
|
||||||
|
|
||||||
|
.. code-block:: cpp
|
||||||
|
|
||||||
|
m.def("floats_only", [](double f) { return 0.5 * f; }, py::arg("f").noconvert());
|
||||||
|
m.def("floats_preferred", [](double f) { return 0.5 * f; }, py::arg("f"));
|
||||||
|
|
||||||
|
Attempting the call the second function (the one without ``.noconvert()``) with
|
||||||
|
an integer will succeed, but attempting to call the ``.noconvert()`` version
|
||||||
|
will fail with a ``TypeError``:
|
||||||
|
|
||||||
|
.. code-block:: pycon
|
||||||
|
|
||||||
|
>>> floats_preferred(4)
|
||||||
|
2.0
|
||||||
|
>>> floats_only(4)
|
||||||
|
Traceback (most recent call last):
|
||||||
|
File "<stdin>", line 1, in <module>
|
||||||
|
TypeError: floats_only(): incompatible function arguments. The following argument types are supported:
|
||||||
|
1. (f: float) -> float
|
||||||
|
|
||||||
|
Invoked with: 4
|
||||||
|
|
||||||
|
You may, of course, combine this with the :var:`_a` shorthand notation (see
|
||||||
|
:ref:`keyword_args`) and/or :ref:`default_args`. It is also permitted to omit
|
||||||
|
the argument name by using the ``py::arg()`` constructor without an argument
|
||||||
|
name, i.e. by specifying ``py::arg().noconvert()``.
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
|
||||||
|
When specifying ``py::arg`` options it is necessary to provide the same
|
||||||
|
number of options as the bound function has arguments. Thus if you want to
|
||||||
|
enable no-convert behaviour for just one of several arguments, you will
|
||||||
|
need to specify a ``py::arg()`` annotation for each argument with the
|
||||||
|
no-convert argument modified to ``py::arg().noconvert()``.
|
||||||
|
|
||||||
|
.. _none_arguments:
|
||||||
|
|
||||||
|
Allow/Prohibiting None arguments
|
||||||
|
================================
|
||||||
|
|
||||||
|
When a C++ type registered with :class:`py::class_` is passed as an argument to
|
||||||
|
a function taking the instance as pointer or shared holder (e.g. ``shared_ptr``
|
||||||
|
or a custom, copyable holder as described in :ref:`smart_pointers`), pybind
|
||||||
|
allows ``None`` to be passed from Python which results in calling the C++
|
||||||
|
function with ``nullptr`` (or an empty holder) for the argument.
|
||||||
|
|
||||||
|
To explicitly enable or disable this behaviour, using the
|
||||||
|
``.none`` method of the :class:`py::arg` object:
|
||||||
|
|
||||||
|
.. code-block:: cpp
|
||||||
|
|
||||||
|
py::class_<Dog>(m, "Dog").def(py::init<>());
|
||||||
|
py::class_<Cat>(m, "Cat").def(py::init<>());
|
||||||
|
m.def("bark", [](Dog *dog) -> std::string {
|
||||||
|
if (dog) return "woof!"; /* Called with a Dog instance */
|
||||||
|
else return "(no dog)"; /* Called with None, dog == nullptr */
|
||||||
|
}, py::arg("dog").none(true));
|
||||||
|
m.def("meow", [](Cat *cat) -> std::string {
|
||||||
|
// Can't be called with None argument
|
||||||
|
return "meow";
|
||||||
|
}, py::arg("cat").none(false));
|
||||||
|
|
||||||
|
With the above, the Python call ``bark(None)`` will return the string ``"(no
|
||||||
|
dog)"``, while attempting to call ``meow(None)`` will raise a ``TypeError``:
|
||||||
|
|
||||||
|
.. code-block:: pycon
|
||||||
|
|
||||||
|
>>> from animals import Dog, Cat, bark, meow
|
||||||
|
>>> bark(Dog())
|
||||||
|
'woof!'
|
||||||
|
>>> meow(Cat())
|
||||||
|
'meow'
|
||||||
|
>>> bark(None)
|
||||||
|
'(no dog)'
|
||||||
|
>>> meow(None)
|
||||||
|
Traceback (most recent call last):
|
||||||
|
File "<stdin>", line 1, in <module>
|
||||||
|
TypeError: meow(): incompatible function arguments. The following argument types are supported:
|
||||||
|
1. (cat: animals.Cat) -> str
|
||||||
|
|
||||||
|
Invoked with: None
|
||||||
|
|
||||||
|
The default behaviour when the tag is unspecified is to allow ``None``.
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
|
||||||
|
Even when ``.none(true)`` is specified for an argument, ``None`` will be converted to a
|
||||||
|
``nullptr`` *only* for custom and :ref:`opaque <opaque>` types. Pointers to built-in types
|
||||||
|
(``double *``, ``int *``, ...) and STL types (``std::vector<T> *``, ...; if ``pybind11/stl.h``
|
||||||
|
is included) are copied when converted to C++ (see :doc:`/advanced/cast/overview`) and will
|
||||||
|
not allow ``None`` as argument. To pass optional argument of these copied types consider
|
||||||
|
using ``std::optional<T>``
|
||||||
|
|
||||||
|
Overload resolution order
|
||||||
|
=========================
|
||||||
|
|
||||||
|
When a function or method with multiple overloads is called from Python,
|
||||||
|
pybind11 determines which overload to call in two passes. The first pass
|
||||||
|
attempts to call each overload without allowing argument conversion (as if
|
||||||
|
every argument had been specified as ``py::arg().noconvert()`` as described
|
||||||
|
above).
|
||||||
|
|
||||||
|
If no overload succeeds in the no-conversion first pass, a second pass is
|
||||||
|
attempted in which argument conversion is allowed (except where prohibited via
|
||||||
|
an explicit ``py::arg().noconvert()`` attribute in the function definition).
|
||||||
|
|
||||||
|
If the second pass also fails a ``TypeError`` is raised.
|
||||||
|
|
||||||
|
Within each pass, overloads are tried in the order they were registered with
|
||||||
|
pybind11.
|
||||||
|
|
||||||
|
What this means in practice is that pybind11 will prefer any overload that does
|
||||||
|
not require conversion of arguments to an overload that does, but otherwise prefers
|
||||||
|
earlier-defined overloads to later-defined ones.
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
|
||||||
|
pybind11 does *not* further prioritize based on the number/pattern of
|
||||||
|
overloaded arguments. That is, pybind11 does not prioritize a function
|
||||||
|
requiring one conversion over one requiring three, but only prioritizes
|
||||||
|
overloads requiring no conversion at all to overloads that require
|
||||||
|
conversion of at least one argument.
|
306
3rdparty/pybind11/docs/advanced/misc.rst
vendored
Normal file
306
3rdparty/pybind11/docs/advanced/misc.rst
vendored
Normal file
@ -0,0 +1,306 @@
|
|||||||
|
Miscellaneous
|
||||||
|
#############
|
||||||
|
|
||||||
|
.. _macro_notes:
|
||||||
|
|
||||||
|
General notes regarding convenience macros
|
||||||
|
==========================================
|
||||||
|
|
||||||
|
pybind11 provides a few convenience macros such as
|
||||||
|
:func:`PYBIND11_DECLARE_HOLDER_TYPE` and ``PYBIND11_OVERLOAD_*``. Since these
|
||||||
|
are "just" macros that are evaluated in the preprocessor (which has no concept
|
||||||
|
of types), they *will* get confused by commas in a template argument; for
|
||||||
|
example, consider:
|
||||||
|
|
||||||
|
.. code-block:: cpp
|
||||||
|
|
||||||
|
PYBIND11_OVERLOAD(MyReturnType<T1, T2>, Class<T3, T4>, func)
|
||||||
|
|
||||||
|
The limitation of the C preprocessor interprets this as five arguments (with new
|
||||||
|
arguments beginning after each comma) rather than three. To get around this,
|
||||||
|
there are two alternatives: you can use a type alias, or you can wrap the type
|
||||||
|
using the ``PYBIND11_TYPE`` macro:
|
||||||
|
|
||||||
|
.. code-block:: cpp
|
||||||
|
|
||||||
|
// Version 1: using a type alias
|
||||||
|
using ReturnType = MyReturnType<T1, T2>;
|
||||||
|
using ClassType = Class<T3, T4>;
|
||||||
|
PYBIND11_OVERLOAD(ReturnType, ClassType, func);
|
||||||
|
|
||||||
|
// Version 2: using the PYBIND11_TYPE macro:
|
||||||
|
PYBIND11_OVERLOAD(PYBIND11_TYPE(MyReturnType<T1, T2>),
|
||||||
|
PYBIND11_TYPE(Class<T3, T4>), func)
|
||||||
|
|
||||||
|
The ``PYBIND11_MAKE_OPAQUE`` macro does *not* require the above workarounds.
|
||||||
|
|
||||||
|
.. _gil:
|
||||||
|
|
||||||
|
Global Interpreter Lock (GIL)
|
||||||
|
=============================
|
||||||
|
|
||||||
|
When calling a C++ function from Python, the GIL is always held.
|
||||||
|
The classes :class:`gil_scoped_release` and :class:`gil_scoped_acquire` can be
|
||||||
|
used to acquire and release the global interpreter lock in the body of a C++
|
||||||
|
function call. In this way, long-running C++ code can be parallelized using
|
||||||
|
multiple Python threads. Taking :ref:`overriding_virtuals` as an example, this
|
||||||
|
could be realized as follows (important changes highlighted):
|
||||||
|
|
||||||
|
.. code-block:: cpp
|
||||||
|
:emphasize-lines: 8,9,31,32
|
||||||
|
|
||||||
|
class PyAnimal : public Animal {
|
||||||
|
public:
|
||||||
|
/* Inherit the constructors */
|
||||||
|
using Animal::Animal;
|
||||||
|
|
||||||
|
/* Trampoline (need one for each virtual function) */
|
||||||
|
std::string go(int n_times) {
|
||||||
|
/* Acquire GIL before calling Python code */
|
||||||
|
py::gil_scoped_acquire acquire;
|
||||||
|
|
||||||
|
PYBIND11_OVERLOAD_PURE(
|
||||||
|
std::string, /* Return type */
|
||||||
|
Animal, /* Parent class */
|
||||||
|
go, /* Name of function */
|
||||||
|
n_times /* Argument(s) */
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
PYBIND11_MODULE(example, m) {
|
||||||
|
py::class_<Animal, PyAnimal> animal(m, "Animal");
|
||||||
|
animal
|
||||||
|
.def(py::init<>())
|
||||||
|
.def("go", &Animal::go);
|
||||||
|
|
||||||
|
py::class_<Dog>(m, "Dog", animal)
|
||||||
|
.def(py::init<>());
|
||||||
|
|
||||||
|
m.def("call_go", [](Animal *animal) -> std::string {
|
||||||
|
/* Release GIL before calling into (potentially long-running) C++ code */
|
||||||
|
py::gil_scoped_release release;
|
||||||
|
return call_go(animal);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
The ``call_go`` wrapper can also be simplified using the `call_guard` policy
|
||||||
|
(see :ref:`call_policies`) which yields the same result:
|
||||||
|
|
||||||
|
.. code-block:: cpp
|
||||||
|
|
||||||
|
m.def("call_go", &call_go, py::call_guard<py::gil_scoped_release>());
|
||||||
|
|
||||||
|
|
||||||
|
Binding sequence data types, iterators, the slicing protocol, etc.
|
||||||
|
==================================================================
|
||||||
|
|
||||||
|
Please refer to the supplemental example for details.
|
||||||
|
|
||||||
|
.. seealso::
|
||||||
|
|
||||||
|
The file :file:`tests/test_sequences_and_iterators.cpp` contains a
|
||||||
|
complete example that shows how to bind a sequence data type, including
|
||||||
|
length queries (``__len__``), iterators (``__iter__``), the slicing
|
||||||
|
protocol and other kinds of useful operations.
|
||||||
|
|
||||||
|
|
||||||
|
Partitioning code over multiple extension modules
|
||||||
|
=================================================
|
||||||
|
|
||||||
|
It's straightforward to split binding code over multiple extension modules,
|
||||||
|
while referencing types that are declared elsewhere. Everything "just" works
|
||||||
|
without any special precautions. One exception to this rule occurs when
|
||||||
|
extending a type declared in another extension module. Recall the basic example
|
||||||
|
from Section :ref:`inheritance`.
|
||||||
|
|
||||||
|
.. code-block:: cpp
|
||||||
|
|
||||||
|
py::class_<Pet> pet(m, "Pet");
|
||||||
|
pet.def(py::init<const std::string &>())
|
||||||
|
.def_readwrite("name", &Pet::name);
|
||||||
|
|
||||||
|
py::class_<Dog>(m, "Dog", pet /* <- specify parent */)
|
||||||
|
.def(py::init<const std::string &>())
|
||||||
|
.def("bark", &Dog::bark);
|
||||||
|
|
||||||
|
Suppose now that ``Pet`` bindings are defined in a module named ``basic``,
|
||||||
|
whereas the ``Dog`` bindings are defined somewhere else. The challenge is of
|
||||||
|
course that the variable ``pet`` is not available anymore though it is needed
|
||||||
|
to indicate the inheritance relationship to the constructor of ``class_<Dog>``.
|
||||||
|
However, it can be acquired as follows:
|
||||||
|
|
||||||
|
.. code-block:: cpp
|
||||||
|
|
||||||
|
py::object pet = (py::object) py::module::import("basic").attr("Pet");
|
||||||
|
|
||||||
|
py::class_<Dog>(m, "Dog", pet)
|
||||||
|
.def(py::init<const std::string &>())
|
||||||
|
.def("bark", &Dog::bark);
|
||||||
|
|
||||||
|
Alternatively, you can specify the base class as a template parameter option to
|
||||||
|
``class_``, which performs an automated lookup of the corresponding Python
|
||||||
|
type. Like the above code, however, this also requires invoking the ``import``
|
||||||
|
function once to ensure that the pybind11 binding code of the module ``basic``
|
||||||
|
has been executed:
|
||||||
|
|
||||||
|
.. code-block:: cpp
|
||||||
|
|
||||||
|
py::module::import("basic");
|
||||||
|
|
||||||
|
py::class_<Dog, Pet>(m, "Dog")
|
||||||
|
.def(py::init<const std::string &>())
|
||||||
|
.def("bark", &Dog::bark);
|
||||||
|
|
||||||
|
Naturally, both methods will fail when there are cyclic dependencies.
|
||||||
|
|
||||||
|
Note that pybind11 code compiled with hidden-by-default symbol visibility (e.g.
|
||||||
|
via the command line flag ``-fvisibility=hidden`` on GCC/Clang), which is
|
||||||
|
required for proper pybind11 functionality, can interfere with the ability to
|
||||||
|
access types defined in another extension module. Working around this requires
|
||||||
|
manually exporting types that are accessed by multiple extension modules;
|
||||||
|
pybind11 provides a macro to do just this:
|
||||||
|
|
||||||
|
.. code-block:: cpp
|
||||||
|
|
||||||
|
class PYBIND11_EXPORT Dog : public Animal {
|
||||||
|
...
|
||||||
|
};
|
||||||
|
|
||||||
|
Note also that it is possible (although would rarely be required) to share arbitrary
|
||||||
|
C++ objects between extension modules at runtime. Internal library data is shared
|
||||||
|
between modules using capsule machinery [#f6]_ which can be also utilized for
|
||||||
|
storing, modifying and accessing user-defined data. Note that an extension module
|
||||||
|
will "see" other extensions' data if and only if they were built with the same
|
||||||
|
pybind11 version. Consider the following example:
|
||||||
|
|
||||||
|
.. code-block:: cpp
|
||||||
|
|
||||||
|
auto data = (MyData *) py::get_shared_data("mydata");
|
||||||
|
if (!data)
|
||||||
|
data = (MyData *) py::set_shared_data("mydata", new MyData(42));
|
||||||
|
|
||||||
|
If the above snippet was used in several separately compiled extension modules,
|
||||||
|
the first one to be imported would create a ``MyData`` instance and associate
|
||||||
|
a ``"mydata"`` key with a pointer to it. Extensions that are imported later
|
||||||
|
would be then able to access the data behind the same pointer.
|
||||||
|
|
||||||
|
.. [#f6] https://docs.python.org/3/extending/extending.html#using-capsules
|
||||||
|
|
||||||
|
Module Destructors
|
||||||
|
==================
|
||||||
|
|
||||||
|
pybind11 does not provide an explicit mechanism to invoke cleanup code at
|
||||||
|
module destruction time. In rare cases where such functionality is required, it
|
||||||
|
is possible to emulate it using Python capsules or weak references with a
|
||||||
|
destruction callback.
|
||||||
|
|
||||||
|
.. code-block:: cpp
|
||||||
|
|
||||||
|
auto cleanup_callback = []() {
|
||||||
|
// perform cleanup here -- this function is called with the GIL held
|
||||||
|
};
|
||||||
|
|
||||||
|
m.add_object("_cleanup", py::capsule(cleanup_callback));
|
||||||
|
|
||||||
|
This approach has the potential downside that instances of classes exposed
|
||||||
|
within the module may still be alive when the cleanup callback is invoked
|
||||||
|
(whether this is acceptable will generally depend on the application).
|
||||||
|
|
||||||
|
Alternatively, the capsule may also be stashed within a type object, which
|
||||||
|
ensures that it not called before all instances of that type have been
|
||||||
|
collected:
|
||||||
|
|
||||||
|
.. code-block:: cpp
|
||||||
|
|
||||||
|
auto cleanup_callback = []() { /* ... */ };
|
||||||
|
m.attr("BaseClass").attr("_cleanup") = py::capsule(cleanup_callback);
|
||||||
|
|
||||||
|
Both approaches also expose a potentially dangerous ``_cleanup`` attribute in
|
||||||
|
Python, which may be undesirable from an API standpoint (a premature explicit
|
||||||
|
call from Python might lead to undefined behavior). Yet another approach that
|
||||||
|
avoids this issue involves weak reference with a cleanup callback:
|
||||||
|
|
||||||
|
.. code-block:: cpp
|
||||||
|
|
||||||
|
// Register a callback function that is invoked when the BaseClass object is colelcted
|
||||||
|
py::cpp_function cleanup_callback(
|
||||||
|
[](py::handle weakref) {
|
||||||
|
// perform cleanup here -- this function is called with the GIL held
|
||||||
|
|
||||||
|
weakref.dec_ref(); // release weak reference
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
// Create a weak reference with a cleanup callback and initially leak it
|
||||||
|
(void) py::weakref(m.attr("BaseClass"), cleanup_callback).release();
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
|
||||||
|
PyPy (at least version 5.9) does not garbage collect objects when the
|
||||||
|
interpreter exits. An alternative approach (which also works on CPython) is to use
|
||||||
|
the :py:mod:`atexit` module [#f7]_, for example:
|
||||||
|
|
||||||
|
.. code-block:: cpp
|
||||||
|
|
||||||
|
auto atexit = py::module::import("atexit");
|
||||||
|
atexit.attr("register")(py::cpp_function([]() {
|
||||||
|
// perform cleanup here -- this function is called with the GIL held
|
||||||
|
}));
|
||||||
|
|
||||||
|
.. [#f7] https://docs.python.org/3/library/atexit.html
|
||||||
|
|
||||||
|
|
||||||
|
Generating documentation using Sphinx
|
||||||
|
=====================================
|
||||||
|
|
||||||
|
Sphinx [#f4]_ has the ability to inspect the signatures and documentation
|
||||||
|
strings in pybind11-based extension modules to automatically generate beautiful
|
||||||
|
documentation in a variety formats. The python_example repository [#f5]_ contains a
|
||||||
|
simple example repository which uses this approach.
|
||||||
|
|
||||||
|
There are two potential gotchas when using this approach: first, make sure that
|
||||||
|
the resulting strings do not contain any :kbd:`TAB` characters, which break the
|
||||||
|
docstring parsing routines. You may want to use C++11 raw string literals,
|
||||||
|
which are convenient for multi-line comments. Conveniently, any excess
|
||||||
|
indentation will be automatically be removed by Sphinx. However, for this to
|
||||||
|
work, it is important that all lines are indented consistently, i.e.:
|
||||||
|
|
||||||
|
.. code-block:: cpp
|
||||||
|
|
||||||
|
// ok
|
||||||
|
m.def("foo", &foo, R"mydelimiter(
|
||||||
|
The foo function
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
----------
|
||||||
|
)mydelimiter");
|
||||||
|
|
||||||
|
// *not ok*
|
||||||
|
m.def("foo", &foo, R"mydelimiter(The foo function
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
----------
|
||||||
|
)mydelimiter");
|
||||||
|
|
||||||
|
By default, pybind11 automatically generates and prepends a signature to the docstring of a function
|
||||||
|
registered with ``module::def()`` and ``class_::def()``. Sometimes this
|
||||||
|
behavior is not desirable, because you want to provide your own signature or remove
|
||||||
|
the docstring completely to exclude the function from the Sphinx documentation.
|
||||||
|
The class ``options`` allows you to selectively suppress auto-generated signatures:
|
||||||
|
|
||||||
|
.. code-block:: cpp
|
||||||
|
|
||||||
|
PYBIND11_MODULE(example, m) {
|
||||||
|
py::options options;
|
||||||
|
options.disable_function_signatures();
|
||||||
|
|
||||||
|
m.def("add", [](int a, int b) { return a + b; }, "A function which adds two numbers");
|
||||||
|
}
|
||||||
|
|
||||||
|
Note that changes to the settings affect only function bindings created during the
|
||||||
|
lifetime of the ``options`` instance. When it goes out of scope at the end of the module's init function,
|
||||||
|
the default settings are restored to prevent unwanted side effects.
|
||||||
|
|
||||||
|
.. [#f4] http://www.sphinx-doc.org
|
||||||
|
.. [#f5] http://github.com/pybind/python_example
|
13
3rdparty/pybind11/docs/advanced/pycpp/index.rst
vendored
Normal file
13
3rdparty/pybind11/docs/advanced/pycpp/index.rst
vendored
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
Python C++ interface
|
||||||
|
####################
|
||||||
|
|
||||||
|
pybind11 exposes Python types and functions using thin C++ wrappers, which
|
||||||
|
makes it possible to conveniently call Python code from C++ without resorting
|
||||||
|
to Python's C API.
|
||||||
|
|
||||||
|
.. toctree::
|
||||||
|
:maxdepth: 2
|
||||||
|
|
||||||
|
object
|
||||||
|
numpy
|
||||||
|
utilities
|
386
3rdparty/pybind11/docs/advanced/pycpp/numpy.rst
vendored
Normal file
386
3rdparty/pybind11/docs/advanced/pycpp/numpy.rst
vendored
Normal file
@ -0,0 +1,386 @@
|
|||||||
|
.. _numpy:
|
||||||
|
|
||||||
|
NumPy
|
||||||
|
#####
|
||||||
|
|
||||||
|
Buffer protocol
|
||||||
|
===============
|
||||||
|
|
||||||
|
Python supports an extremely general and convenient approach for exchanging
|
||||||
|
data between plugin libraries. Types can expose a buffer view [#f2]_, which
|
||||||
|
provides fast direct access to the raw internal data representation. Suppose we
|
||||||
|
want to bind the following simplistic Matrix class:
|
||||||
|
|
||||||
|
.. code-block:: cpp
|
||||||
|
|
||||||
|
class Matrix {
|
||||||
|
public:
|
||||||
|
Matrix(size_t rows, size_t cols) : m_rows(rows), m_cols(cols) {
|
||||||
|
m_data = new float[rows*cols];
|
||||||
|
}
|
||||||
|
float *data() { return m_data; }
|
||||||
|
size_t rows() const { return m_rows; }
|
||||||
|
size_t cols() const { return m_cols; }
|
||||||
|
private:
|
||||||
|
size_t m_rows, m_cols;
|
||||||
|
float *m_data;
|
||||||
|
};
|
||||||
|
|
||||||
|
The following binding code exposes the ``Matrix`` contents as a buffer object,
|
||||||
|
making it possible to cast Matrices into NumPy arrays. It is even possible to
|
||||||
|
completely avoid copy operations with Python expressions like
|
||||||
|
``np.array(matrix_instance, copy = False)``.
|
||||||
|
|
||||||
|
.. code-block:: cpp
|
||||||
|
|
||||||
|
py::class_<Matrix>(m, "Matrix", py::buffer_protocol())
|
||||||
|
.def_buffer([](Matrix &m) -> py::buffer_info {
|
||||||
|
return py::buffer_info(
|
||||||
|
m.data(), /* Pointer to buffer */
|
||||||
|
sizeof(float), /* Size of one scalar */
|
||||||
|
py::format_descriptor<float>::format(), /* Python struct-style format descriptor */
|
||||||
|
2, /* Number of dimensions */
|
||||||
|
{ m.rows(), m.cols() }, /* Buffer dimensions */
|
||||||
|
{ sizeof(float) * m.cols(), /* Strides (in bytes) for each index */
|
||||||
|
sizeof(float) }
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
Supporting the buffer protocol in a new type involves specifying the special
|
||||||
|
``py::buffer_protocol()`` tag in the ``py::class_`` constructor and calling the
|
||||||
|
``def_buffer()`` method with a lambda function that creates a
|
||||||
|
``py::buffer_info`` description record on demand describing a given matrix
|
||||||
|
instance. The contents of ``py::buffer_info`` mirror the Python buffer protocol
|
||||||
|
specification.
|
||||||
|
|
||||||
|
.. code-block:: cpp
|
||||||
|
|
||||||
|
struct buffer_info {
|
||||||
|
void *ptr;
|
||||||
|
ssize_t itemsize;
|
||||||
|
std::string format;
|
||||||
|
ssize_t ndim;
|
||||||
|
std::vector<ssize_t> shape;
|
||||||
|
std::vector<ssize_t> strides;
|
||||||
|
};
|
||||||
|
|
||||||
|
To create a C++ function that can take a Python buffer object as an argument,
|
||||||
|
simply use the type ``py::buffer`` as one of its arguments. Buffers can exist
|
||||||
|
in a great variety of configurations, hence some safety checks are usually
|
||||||
|
necessary in the function body. Below, you can see an basic example on how to
|
||||||
|
define a custom constructor for the Eigen double precision matrix
|
||||||
|
(``Eigen::MatrixXd``) type, which supports initialization from compatible
|
||||||
|
buffer objects (e.g. a NumPy matrix).
|
||||||
|
|
||||||
|
.. code-block:: cpp
|
||||||
|
|
||||||
|
/* Bind MatrixXd (or some other Eigen type) to Python */
|
||||||
|
typedef Eigen::MatrixXd Matrix;
|
||||||
|
|
||||||
|
typedef Matrix::Scalar Scalar;
|
||||||
|
constexpr bool rowMajor = Matrix::Flags & Eigen::RowMajorBit;
|
||||||
|
|
||||||
|
py::class_<Matrix>(m, "Matrix", py::buffer_protocol())
|
||||||
|
.def("__init__", [](Matrix &m, py::buffer b) {
|
||||||
|
typedef Eigen::Stride<Eigen::Dynamic, Eigen::Dynamic> Strides;
|
||||||
|
|
||||||
|
/* Request a buffer descriptor from Python */
|
||||||
|
py::buffer_info info = b.request();
|
||||||
|
|
||||||
|
/* Some sanity checks ... */
|
||||||
|
if (info.format != py::format_descriptor<Scalar>::format())
|
||||||
|
throw std::runtime_error("Incompatible format: expected a double array!");
|
||||||
|
|
||||||
|
if (info.ndim != 2)
|
||||||
|
throw std::runtime_error("Incompatible buffer dimension!");
|
||||||
|
|
||||||
|
auto strides = Strides(
|
||||||
|
info.strides[rowMajor ? 0 : 1] / (py::ssize_t)sizeof(Scalar),
|
||||||
|
info.strides[rowMajor ? 1 : 0] / (py::ssize_t)sizeof(Scalar));
|
||||||
|
|
||||||
|
auto map = Eigen::Map<Matrix, 0, Strides>(
|
||||||
|
static_cast<Scalar *>(info.ptr), info.shape[0], info.shape[1], strides);
|
||||||
|
|
||||||
|
new (&m) Matrix(map);
|
||||||
|
});
|
||||||
|
|
||||||
|
For reference, the ``def_buffer()`` call for this Eigen data type should look
|
||||||
|
as follows:
|
||||||
|
|
||||||
|
.. code-block:: cpp
|
||||||
|
|
||||||
|
.def_buffer([](Matrix &m) -> py::buffer_info {
|
||||||
|
return py::buffer_info(
|
||||||
|
m.data(), /* Pointer to buffer */
|
||||||
|
sizeof(Scalar), /* Size of one scalar */
|
||||||
|
py::format_descriptor<Scalar>::format(), /* Python struct-style format descriptor */
|
||||||
|
2, /* Number of dimensions */
|
||||||
|
{ m.rows(), m.cols() }, /* Buffer dimensions */
|
||||||
|
{ sizeof(Scalar) * (rowMajor ? m.cols() : 1),
|
||||||
|
sizeof(Scalar) * (rowMajor ? 1 : m.rows()) }
|
||||||
|
/* Strides (in bytes) for each index */
|
||||||
|
);
|
||||||
|
})
|
||||||
|
|
||||||
|
For a much easier approach of binding Eigen types (although with some
|
||||||
|
limitations), refer to the section on :doc:`/advanced/cast/eigen`.
|
||||||
|
|
||||||
|
.. seealso::
|
||||||
|
|
||||||
|
The file :file:`tests/test_buffers.cpp` contains a complete example
|
||||||
|
that demonstrates using the buffer protocol with pybind11 in more detail.
|
||||||
|
|
||||||
|
.. [#f2] http://docs.python.org/3/c-api/buffer.html
|
||||||
|
|
||||||
|
Arrays
|
||||||
|
======
|
||||||
|
|
||||||
|
By exchanging ``py::buffer`` with ``py::array`` in the above snippet, we can
|
||||||
|
restrict the function so that it only accepts NumPy arrays (rather than any
|
||||||
|
type of Python object satisfying the buffer protocol).
|
||||||
|
|
||||||
|
In many situations, we want to define a function which only accepts a NumPy
|
||||||
|
array of a certain data type. This is possible via the ``py::array_t<T>``
|
||||||
|
template. For instance, the following function requires the argument to be a
|
||||||
|
NumPy array containing double precision values.
|
||||||
|
|
||||||
|
.. code-block:: cpp
|
||||||
|
|
||||||
|
void f(py::array_t<double> array);
|
||||||
|
|
||||||
|
When it is invoked with a different type (e.g. an integer or a list of
|
||||||
|
integers), the binding code will attempt to cast the input into a NumPy array
|
||||||
|
of the requested type. Note that this feature requires the
|
||||||
|
:file:`pybind11/numpy.h` header to be included.
|
||||||
|
|
||||||
|
Data in NumPy arrays is not guaranteed to packed in a dense manner;
|
||||||
|
furthermore, entries can be separated by arbitrary column and row strides.
|
||||||
|
Sometimes, it can be useful to require a function to only accept dense arrays
|
||||||
|
using either the C (row-major) or Fortran (column-major) ordering. This can be
|
||||||
|
accomplished via a second template argument with values ``py::array::c_style``
|
||||||
|
or ``py::array::f_style``.
|
||||||
|
|
||||||
|
.. code-block:: cpp
|
||||||
|
|
||||||
|
void f(py::array_t<double, py::array::c_style | py::array::forcecast> array);
|
||||||
|
|
||||||
|
The ``py::array::forcecast`` argument is the default value of the second
|
||||||
|
template parameter, and it ensures that non-conforming arguments are converted
|
||||||
|
into an array satisfying the specified requirements instead of trying the next
|
||||||
|
function overload.
|
||||||
|
|
||||||
|
Structured types
|
||||||
|
================
|
||||||
|
|
||||||
|
In order for ``py::array_t`` to work with structured (record) types, we first
|
||||||
|
need to register the memory layout of the type. This can be done via
|
||||||
|
``PYBIND11_NUMPY_DTYPE`` macro, called in the plugin definition code, which
|
||||||
|
expects the type followed by field names:
|
||||||
|
|
||||||
|
.. code-block:: cpp
|
||||||
|
|
||||||
|
struct A {
|
||||||
|
int x;
|
||||||
|
double y;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct B {
|
||||||
|
int z;
|
||||||
|
A a;
|
||||||
|
};
|
||||||
|
|
||||||
|
// ...
|
||||||
|
PYBIND11_MODULE(test, m) {
|
||||||
|
// ...
|
||||||
|
|
||||||
|
PYBIND11_NUMPY_DTYPE(A, x, y);
|
||||||
|
PYBIND11_NUMPY_DTYPE(B, z, a);
|
||||||
|
/* now both A and B can be used as template arguments to py::array_t */
|
||||||
|
}
|
||||||
|
|
||||||
|
The structure should consist of fundamental arithmetic types, ``std::complex``,
|
||||||
|
previously registered substructures, and arrays of any of the above. Both C++
|
||||||
|
arrays and ``std::array`` are supported. While there is a static assertion to
|
||||||
|
prevent many types of unsupported structures, it is still the user's
|
||||||
|
responsibility to use only "plain" structures that can be safely manipulated as
|
||||||
|
raw memory without violating invariants.
|
||||||
|
|
||||||
|
Vectorizing functions
|
||||||
|
=====================
|
||||||
|
|
||||||
|
Suppose we want to bind a function with the following signature to Python so
|
||||||
|
that it can process arbitrary NumPy array arguments (vectors, matrices, general
|
||||||
|
N-D arrays) in addition to its normal arguments:
|
||||||
|
|
||||||
|
.. code-block:: cpp
|
||||||
|
|
||||||
|
double my_func(int x, float y, double z);
|
||||||
|
|
||||||
|
After including the ``pybind11/numpy.h`` header, this is extremely simple:
|
||||||
|
|
||||||
|
.. code-block:: cpp
|
||||||
|
|
||||||
|
m.def("vectorized_func", py::vectorize(my_func));
|
||||||
|
|
||||||
|
Invoking the function like below causes 4 calls to be made to ``my_func`` with
|
||||||
|
each of the array elements. The significant advantage of this compared to
|
||||||
|
solutions like ``numpy.vectorize()`` is that the loop over the elements runs
|
||||||
|
entirely on the C++ side and can be crunched down into a tight, optimized loop
|
||||||
|
by the compiler. The result is returned as a NumPy array of type
|
||||||
|
``numpy.dtype.float64``.
|
||||||
|
|
||||||
|
.. code-block:: pycon
|
||||||
|
|
||||||
|
>>> x = np.array([[1, 3],[5, 7]])
|
||||||
|
>>> y = np.array([[2, 4],[6, 8]])
|
||||||
|
>>> z = 3
|
||||||
|
>>> result = vectorized_func(x, y, z)
|
||||||
|
|
||||||
|
The scalar argument ``z`` is transparently replicated 4 times. The input
|
||||||
|
arrays ``x`` and ``y`` are automatically converted into the right types (they
|
||||||
|
are of type ``numpy.dtype.int64`` but need to be ``numpy.dtype.int32`` and
|
||||||
|
``numpy.dtype.float32``, respectively).
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
|
||||||
|
Only arithmetic, complex, and POD types passed by value or by ``const &``
|
||||||
|
reference are vectorized; all other arguments are passed through as-is.
|
||||||
|
Functions taking rvalue reference arguments cannot be vectorized.
|
||||||
|
|
||||||
|
In cases where the computation is too complicated to be reduced to
|
||||||
|
``vectorize``, it will be necessary to create and access the buffer contents
|
||||||
|
manually. The following snippet contains a complete example that shows how this
|
||||||
|
works (the code is somewhat contrived, since it could have been done more
|
||||||
|
simply using ``vectorize``).
|
||||||
|
|
||||||
|
.. code-block:: cpp
|
||||||
|
|
||||||
|
#include <pybind11/pybind11.h>
|
||||||
|
#include <pybind11/numpy.h>
|
||||||
|
|
||||||
|
namespace py = pybind11;
|
||||||
|
|
||||||
|
py::array_t<double> add_arrays(py::array_t<double> input1, py::array_t<double> input2) {
|
||||||
|
py::buffer_info buf1 = input1.request(), buf2 = input2.request();
|
||||||
|
|
||||||
|
if (buf1.ndim != 1 || buf2.ndim != 1)
|
||||||
|
throw std::runtime_error("Number of dimensions must be one");
|
||||||
|
|
||||||
|
if (buf1.size != buf2.size)
|
||||||
|
throw std::runtime_error("Input shapes must match");
|
||||||
|
|
||||||
|
/* No pointer is passed, so NumPy will allocate the buffer */
|
||||||
|
auto result = py::array_t<double>(buf1.size);
|
||||||
|
|
||||||
|
py::buffer_info buf3 = result.request();
|
||||||
|
|
||||||
|
double *ptr1 = (double *) buf1.ptr,
|
||||||
|
*ptr2 = (double *) buf2.ptr,
|
||||||
|
*ptr3 = (double *) buf3.ptr;
|
||||||
|
|
||||||
|
for (size_t idx = 0; idx < buf1.shape[0]; idx++)
|
||||||
|
ptr3[idx] = ptr1[idx] + ptr2[idx];
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
PYBIND11_MODULE(test, m) {
|
||||||
|
m.def("add_arrays", &add_arrays, "Add two NumPy arrays");
|
||||||
|
}
|
||||||
|
|
||||||
|
.. seealso::
|
||||||
|
|
||||||
|
The file :file:`tests/test_numpy_vectorize.cpp` contains a complete
|
||||||
|
example that demonstrates using :func:`vectorize` in more detail.
|
||||||
|
|
||||||
|
Direct access
|
||||||
|
=============
|
||||||
|
|
||||||
|
For performance reasons, particularly when dealing with very large arrays, it
|
||||||
|
is often desirable to directly access array elements without internal checking
|
||||||
|
of dimensions and bounds on every access when indices are known to be already
|
||||||
|
valid. To avoid such checks, the ``array`` class and ``array_t<T>`` template
|
||||||
|
class offer an unchecked proxy object that can be used for this unchecked
|
||||||
|
access through the ``unchecked<N>`` and ``mutable_unchecked<N>`` methods,
|
||||||
|
where ``N`` gives the required dimensionality of the array:
|
||||||
|
|
||||||
|
.. code-block:: cpp
|
||||||
|
|
||||||
|
m.def("sum_3d", [](py::array_t<double> x) {
|
||||||
|
auto r = x.unchecked<3>(); // x must have ndim = 3; can be non-writeable
|
||||||
|
double sum = 0;
|
||||||
|
for (ssize_t i = 0; i < r.shape(0); i++)
|
||||||
|
for (ssize_t j = 0; j < r.shape(1); j++)
|
||||||
|
for (ssize_t k = 0; k < r.shape(2); k++)
|
||||||
|
sum += r(i, j, k);
|
||||||
|
return sum;
|
||||||
|
});
|
||||||
|
m.def("increment_3d", [](py::array_t<double> x) {
|
||||||
|
auto r = x.mutable_unchecked<3>(); // Will throw if ndim != 3 or flags.writeable is false
|
||||||
|
for (ssize_t i = 0; i < r.shape(0); i++)
|
||||||
|
for (ssize_t j = 0; j < r.shape(1); j++)
|
||||||
|
for (ssize_t k = 0; k < r.shape(2); k++)
|
||||||
|
r(i, j, k) += 1.0;
|
||||||
|
}, py::arg().noconvert());
|
||||||
|
|
||||||
|
To obtain the proxy from an ``array`` object, you must specify both the data
|
||||||
|
type and number of dimensions as template arguments, such as ``auto r =
|
||||||
|
myarray.mutable_unchecked<float, 2>()``.
|
||||||
|
|
||||||
|
If the number of dimensions is not known at compile time, you can omit the
|
||||||
|
dimensions template parameter (i.e. calling ``arr_t.unchecked()`` or
|
||||||
|
``arr.unchecked<T>()``. This will give you a proxy object that works in the
|
||||||
|
same way, but results in less optimizable code and thus a small efficiency
|
||||||
|
loss in tight loops.
|
||||||
|
|
||||||
|
Note that the returned proxy object directly references the array's data, and
|
||||||
|
only reads its shape, strides, and writeable flag when constructed. You must
|
||||||
|
take care to ensure that the referenced array is not destroyed or reshaped for
|
||||||
|
the duration of the returned object, typically by limiting the scope of the
|
||||||
|
returned instance.
|
||||||
|
|
||||||
|
The returned proxy object supports some of the same methods as ``py::array`` so
|
||||||
|
that it can be used as a drop-in replacement for some existing, index-checked
|
||||||
|
uses of ``py::array``:
|
||||||
|
|
||||||
|
- ``r.ndim()`` returns the number of dimensions
|
||||||
|
|
||||||
|
- ``r.data(1, 2, ...)`` and ``r.mutable_data(1, 2, ...)``` returns a pointer to
|
||||||
|
the ``const T`` or ``T`` data, respectively, at the given indices. The
|
||||||
|
latter is only available to proxies obtained via ``a.mutable_unchecked()``.
|
||||||
|
|
||||||
|
- ``itemsize()`` returns the size of an item in bytes, i.e. ``sizeof(T)``.
|
||||||
|
|
||||||
|
- ``ndim()`` returns the number of dimensions.
|
||||||
|
|
||||||
|
- ``shape(n)`` returns the size of dimension ``n``
|
||||||
|
|
||||||
|
- ``size()`` returns the total number of elements (i.e. the product of the shapes).
|
||||||
|
|
||||||
|
- ``nbytes()`` returns the number of bytes used by the referenced elements
|
||||||
|
(i.e. ``itemsize()`` times ``size()``).
|
||||||
|
|
||||||
|
.. seealso::
|
||||||
|
|
||||||
|
The file :file:`tests/test_numpy_array.cpp` contains additional examples
|
||||||
|
demonstrating the use of this feature.
|
||||||
|
|
||||||
|
Ellipsis
|
||||||
|
========
|
||||||
|
|
||||||
|
Python 3 provides a convenient ``...`` ellipsis notation that is often used to
|
||||||
|
slice multidimensional arrays. For instance, the following snippet extracts the
|
||||||
|
middle dimensions of a tensor with the first and last index set to zero.
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
a = # a NumPy array
|
||||||
|
b = a[0, ..., 0]
|
||||||
|
|
||||||
|
The function ``py::ellipsis()`` function can be used to perform the same
|
||||||
|
operation on the C++ side:
|
||||||
|
|
||||||
|
.. code-block:: cpp
|
||||||
|
|
||||||
|
py::array a = /* A NumPy array */;
|
||||||
|
py::array b = a[py::make_tuple(0, py::ellipsis(), 0)];
|
170
3rdparty/pybind11/docs/advanced/pycpp/object.rst
vendored
Normal file
170
3rdparty/pybind11/docs/advanced/pycpp/object.rst
vendored
Normal file
@ -0,0 +1,170 @@
|
|||||||
|
Python types
|
||||||
|
############
|
||||||
|
|
||||||
|
Available wrappers
|
||||||
|
==================
|
||||||
|
|
||||||
|
All major Python types are available as thin C++ wrapper classes. These
|
||||||
|
can also be used as function parameters -- see :ref:`python_objects_as_args`.
|
||||||
|
|
||||||
|
Available types include :class:`handle`, :class:`object`, :class:`bool_`,
|
||||||
|
:class:`int_`, :class:`float_`, :class:`str`, :class:`bytes`, :class:`tuple`,
|
||||||
|
:class:`list`, :class:`dict`, :class:`slice`, :class:`none`, :class:`capsule`,
|
||||||
|
:class:`iterable`, :class:`iterator`, :class:`function`, :class:`buffer`,
|
||||||
|
:class:`array`, and :class:`array_t`.
|
||||||
|
|
||||||
|
Casting back and forth
|
||||||
|
======================
|
||||||
|
|
||||||
|
In this kind of mixed code, it is often necessary to convert arbitrary C++
|
||||||
|
types to Python, which can be done using :func:`py::cast`:
|
||||||
|
|
||||||
|
.. code-block:: cpp
|
||||||
|
|
||||||
|
MyClass *cls = ..;
|
||||||
|
py::object obj = py::cast(cls);
|
||||||
|
|
||||||
|
The reverse direction uses the following syntax:
|
||||||
|
|
||||||
|
.. code-block:: cpp
|
||||||
|
|
||||||
|
py::object obj = ...;
|
||||||
|
MyClass *cls = obj.cast<MyClass *>();
|
||||||
|
|
||||||
|
When conversion fails, both directions throw the exception :class:`cast_error`.
|
||||||
|
|
||||||
|
.. _python_libs:
|
||||||
|
|
||||||
|
Accessing Python libraries from C++
|
||||||
|
===================================
|
||||||
|
|
||||||
|
It is also possible to import objects defined in the Python standard
|
||||||
|
library or available in the current Python environment (``sys.path``) and work
|
||||||
|
with these in C++.
|
||||||
|
|
||||||
|
This example obtains a reference to the Python ``Decimal`` class.
|
||||||
|
|
||||||
|
.. code-block:: cpp
|
||||||
|
|
||||||
|
// Equivalent to "from decimal import Decimal"
|
||||||
|
py::object Decimal = py::module::import("decimal").attr("Decimal");
|
||||||
|
|
||||||
|
.. code-block:: cpp
|
||||||
|
|
||||||
|
// Try to import scipy
|
||||||
|
py::object scipy = py::module::import("scipy");
|
||||||
|
return scipy.attr("__version__");
|
||||||
|
|
||||||
|
.. _calling_python_functions:
|
||||||
|
|
||||||
|
Calling Python functions
|
||||||
|
========================
|
||||||
|
|
||||||
|
It is also possible to call Python classes, functions and methods
|
||||||
|
via ``operator()``.
|
||||||
|
|
||||||
|
.. code-block:: cpp
|
||||||
|
|
||||||
|
// Construct a Python object of class Decimal
|
||||||
|
py::object pi = Decimal("3.14159");
|
||||||
|
|
||||||
|
.. code-block:: cpp
|
||||||
|
|
||||||
|
// Use Python to make our directories
|
||||||
|
py::object os = py::module::import("os");
|
||||||
|
py::object makedirs = os.attr("makedirs");
|
||||||
|
makedirs("/tmp/path/to/somewhere");
|
||||||
|
|
||||||
|
One can convert the result obtained from Python to a pure C++ version
|
||||||
|
if a ``py::class_`` or type conversion is defined.
|
||||||
|
|
||||||
|
.. code-block:: cpp
|
||||||
|
|
||||||
|
py::function f = <...>;
|
||||||
|
py::object result_py = f(1234, "hello", some_instance);
|
||||||
|
MyClass &result = result_py.cast<MyClass>();
|
||||||
|
|
||||||
|
.. _calling_python_methods:
|
||||||
|
|
||||||
|
Calling Python methods
|
||||||
|
========================
|
||||||
|
|
||||||
|
To call an object's method, one can again use ``.attr`` to obtain access to the
|
||||||
|
Python method.
|
||||||
|
|
||||||
|
.. code-block:: cpp
|
||||||
|
|
||||||
|
// Calculate e^π in decimal
|
||||||
|
py::object exp_pi = pi.attr("exp")();
|
||||||
|
py::print(py::str(exp_pi));
|
||||||
|
|
||||||
|
In the example above ``pi.attr("exp")`` is a *bound method*: it will always call
|
||||||
|
the method for that same instance of the class. Alternately one can create an
|
||||||
|
*unbound method* via the Python class (instead of instance) and pass the ``self``
|
||||||
|
object explicitly, followed by other arguments.
|
||||||
|
|
||||||
|
.. code-block:: cpp
|
||||||
|
|
||||||
|
py::object decimal_exp = Decimal.attr("exp");
|
||||||
|
|
||||||
|
// Compute the e^n for n=0..4
|
||||||
|
for (int n = 0; n < 5; n++) {
|
||||||
|
py::print(decimal_exp(Decimal(n));
|
||||||
|
}
|
||||||
|
|
||||||
|
Keyword arguments
|
||||||
|
=================
|
||||||
|
|
||||||
|
Keyword arguments are also supported. In Python, there is the usual call syntax:
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
def f(number, say, to):
|
||||||
|
... # function code
|
||||||
|
|
||||||
|
f(1234, say="hello", to=some_instance) # keyword call in Python
|
||||||
|
|
||||||
|
In C++, the same call can be made using:
|
||||||
|
|
||||||
|
.. code-block:: cpp
|
||||||
|
|
||||||
|
using namespace pybind11::literals; // to bring in the `_a` literal
|
||||||
|
f(1234, "say"_a="hello", "to"_a=some_instance); // keyword call in C++
|
||||||
|
|
||||||
|
Unpacking arguments
|
||||||
|
===================
|
||||||
|
|
||||||
|
Unpacking of ``*args`` and ``**kwargs`` is also possible and can be mixed with
|
||||||
|
other arguments:
|
||||||
|
|
||||||
|
.. code-block:: cpp
|
||||||
|
|
||||||
|
// * unpacking
|
||||||
|
py::tuple args = py::make_tuple(1234, "hello", some_instance);
|
||||||
|
f(*args);
|
||||||
|
|
||||||
|
// ** unpacking
|
||||||
|
py::dict kwargs = py::dict("number"_a=1234, "say"_a="hello", "to"_a=some_instance);
|
||||||
|
f(**kwargs);
|
||||||
|
|
||||||
|
// mixed keywords, * and ** unpacking
|
||||||
|
py::tuple args = py::make_tuple(1234);
|
||||||
|
py::dict kwargs = py::dict("to"_a=some_instance);
|
||||||
|
f(*args, "say"_a="hello", **kwargs);
|
||||||
|
|
||||||
|
Generalized unpacking according to PEP448_ is also supported:
|
||||||
|
|
||||||
|
.. code-block:: cpp
|
||||||
|
|
||||||
|
py::dict kwargs1 = py::dict("number"_a=1234);
|
||||||
|
py::dict kwargs2 = py::dict("to"_a=some_instance);
|
||||||
|
f(**kwargs1, "say"_a="hello", **kwargs2);
|
||||||
|
|
||||||
|
.. seealso::
|
||||||
|
|
||||||
|
The file :file:`tests/test_pytypes.cpp` contains a complete
|
||||||
|
example that demonstrates passing native Python types in more detail. The
|
||||||
|
file :file:`tests/test_callbacks.cpp` presents a few examples of calling
|
||||||
|
Python functions from C++, including keywords arguments and unpacking.
|
||||||
|
|
||||||
|
.. _PEP448: https://www.python.org/dev/peps/pep-0448/
|
144
3rdparty/pybind11/docs/advanced/pycpp/utilities.rst
vendored
Normal file
144
3rdparty/pybind11/docs/advanced/pycpp/utilities.rst
vendored
Normal file
@ -0,0 +1,144 @@
|
|||||||
|
Utilities
|
||||||
|
#########
|
||||||
|
|
||||||
|
Using Python's print function in C++
|
||||||
|
====================================
|
||||||
|
|
||||||
|
The usual way to write output in C++ is using ``std::cout`` while in Python one
|
||||||
|
would use ``print``. Since these methods use different buffers, mixing them can
|
||||||
|
lead to output order issues. To resolve this, pybind11 modules can use the
|
||||||
|
:func:`py::print` function which writes to Python's ``sys.stdout`` for consistency.
|
||||||
|
|
||||||
|
Python's ``print`` function is replicated in the C++ API including optional
|
||||||
|
keyword arguments ``sep``, ``end``, ``file``, ``flush``. Everything works as
|
||||||
|
expected in Python:
|
||||||
|
|
||||||
|
.. code-block:: cpp
|
||||||
|
|
||||||
|
py::print(1, 2.0, "three"); // 1 2.0 three
|
||||||
|
py::print(1, 2.0, "three", "sep"_a="-"); // 1-2.0-three
|
||||||
|
|
||||||
|
auto args = py::make_tuple("unpacked", true);
|
||||||
|
py::print("->", *args, "end"_a="<-"); // -> unpacked True <-
|
||||||
|
|
||||||
|
.. _ostream_redirect:
|
||||||
|
|
||||||
|
Capturing standard output from ostream
|
||||||
|
======================================
|
||||||
|
|
||||||
|
Often, a library will use the streams ``std::cout`` and ``std::cerr`` to print,
|
||||||
|
but this does not play well with Python's standard ``sys.stdout`` and ``sys.stderr``
|
||||||
|
redirection. Replacing a library's printing with `py::print <print>` may not
|
||||||
|
be feasible. This can be fixed using a guard around the library function that
|
||||||
|
redirects output to the corresponding Python streams:
|
||||||
|
|
||||||
|
.. code-block:: cpp
|
||||||
|
|
||||||
|
#include <pybind11/iostream.h>
|
||||||
|
|
||||||
|
...
|
||||||
|
|
||||||
|
// Add a scoped redirect for your noisy code
|
||||||
|
m.def("noisy_func", []() {
|
||||||
|
py::scoped_ostream_redirect stream(
|
||||||
|
std::cout, // std::ostream&
|
||||||
|
py::module::import("sys").attr("stdout") // Python output
|
||||||
|
);
|
||||||
|
call_noisy_func();
|
||||||
|
});
|
||||||
|
|
||||||
|
This method respects flushes on the output streams and will flush if needed
|
||||||
|
when the scoped guard is destroyed. This allows the output to be redirected in
|
||||||
|
real time, such as to a Jupyter notebook. The two arguments, the C++ stream and
|
||||||
|
the Python output, are optional, and default to standard output if not given. An
|
||||||
|
extra type, `py::scoped_estream_redirect <scoped_estream_redirect>`, is identical
|
||||||
|
except for defaulting to ``std::cerr`` and ``sys.stderr``; this can be useful with
|
||||||
|
`py::call_guard`, which allows multiple items, but uses the default constructor:
|
||||||
|
|
||||||
|
.. code-block:: py
|
||||||
|
|
||||||
|
// Alternative: Call single function using call guard
|
||||||
|
m.def("noisy_func", &call_noisy_function,
|
||||||
|
py::call_guard<py::scoped_ostream_redirect,
|
||||||
|
py::scoped_estream_redirect>());
|
||||||
|
|
||||||
|
The redirection can also be done in Python with the addition of a context
|
||||||
|
manager, using the `py::add_ostream_redirect() <add_ostream_redirect>` function:
|
||||||
|
|
||||||
|
.. code-block:: cpp
|
||||||
|
|
||||||
|
py::add_ostream_redirect(m, "ostream_redirect");
|
||||||
|
|
||||||
|
The name in Python defaults to ``ostream_redirect`` if no name is passed. This
|
||||||
|
creates the following context manager in Python:
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
with ostream_redirect(stdout=True, stderr=True):
|
||||||
|
noisy_function()
|
||||||
|
|
||||||
|
It defaults to redirecting both streams, though you can use the keyword
|
||||||
|
arguments to disable one of the streams if needed.
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
|
||||||
|
The above methods will not redirect C-level output to file descriptors, such
|
||||||
|
as ``fprintf``. For those cases, you'll need to redirect the file
|
||||||
|
descriptors either directly in C or with Python's ``os.dup2`` function
|
||||||
|
in an operating-system dependent way.
|
||||||
|
|
||||||
|
.. _eval:
|
||||||
|
|
||||||
|
Evaluating Python expressions from strings and files
|
||||||
|
====================================================
|
||||||
|
|
||||||
|
pybind11 provides the `eval`, `exec` and `eval_file` functions to evaluate
|
||||||
|
Python expressions and statements. The following example illustrates how they
|
||||||
|
can be used.
|
||||||
|
|
||||||
|
.. code-block:: cpp
|
||||||
|
|
||||||
|
// At beginning of file
|
||||||
|
#include <pybind11/eval.h>
|
||||||
|
|
||||||
|
...
|
||||||
|
|
||||||
|
// Evaluate in scope of main module
|
||||||
|
py::object scope = py::module::import("__main__").attr("__dict__");
|
||||||
|
|
||||||
|
// Evaluate an isolated expression
|
||||||
|
int result = py::eval("my_variable + 10", scope).cast<int>();
|
||||||
|
|
||||||
|
// Evaluate a sequence of statements
|
||||||
|
py::exec(
|
||||||
|
"print('Hello')\n"
|
||||||
|
"print('world!');",
|
||||||
|
scope);
|
||||||
|
|
||||||
|
// Evaluate the statements in an separate Python file on disk
|
||||||
|
py::eval_file("script.py", scope);
|
||||||
|
|
||||||
|
C++11 raw string literals are also supported and quite handy for this purpose.
|
||||||
|
The only requirement is that the first statement must be on a new line following
|
||||||
|
the raw string delimiter ``R"(``, ensuring all lines have common leading indent:
|
||||||
|
|
||||||
|
.. code-block:: cpp
|
||||||
|
|
||||||
|
py::exec(R"(
|
||||||
|
x = get_answer()
|
||||||
|
if x == 42:
|
||||||
|
print('Hello World!')
|
||||||
|
else:
|
||||||
|
print('Bye!')
|
||||||
|
)", scope
|
||||||
|
);
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
|
||||||
|
`eval` and `eval_file` accept a template parameter that describes how the
|
||||||
|
string/file should be interpreted. Possible choices include ``eval_expr``
|
||||||
|
(isolated expression), ``eval_single_statement`` (a single statement, return
|
||||||
|
value is always ``none``), and ``eval_statements`` (sequence of statements,
|
||||||
|
return value is always ``none``). `eval` defaults to ``eval_expr``,
|
||||||
|
`eval_file` defaults to ``eval_statements`` and `exec` is just a shortcut
|
||||||
|
for ``eval<eval_statements>``.
|
173
3rdparty/pybind11/docs/advanced/smart_ptrs.rst
vendored
Normal file
173
3rdparty/pybind11/docs/advanced/smart_ptrs.rst
vendored
Normal file
@ -0,0 +1,173 @@
|
|||||||
|
Smart pointers
|
||||||
|
##############
|
||||||
|
|
||||||
|
std::unique_ptr
|
||||||
|
===============
|
||||||
|
|
||||||
|
Given a class ``Example`` with Python bindings, it's possible to return
|
||||||
|
instances wrapped in C++11 unique pointers, like so
|
||||||
|
|
||||||
|
.. code-block:: cpp
|
||||||
|
|
||||||
|
std::unique_ptr<Example> create_example() { return std::unique_ptr<Example>(new Example()); }
|
||||||
|
|
||||||
|
.. code-block:: cpp
|
||||||
|
|
||||||
|
m.def("create_example", &create_example);
|
||||||
|
|
||||||
|
In other words, there is nothing special that needs to be done. While returning
|
||||||
|
unique pointers in this way is allowed, it is *illegal* to use them as function
|
||||||
|
arguments. For instance, the following function signature cannot be processed
|
||||||
|
by pybind11.
|
||||||
|
|
||||||
|
.. code-block:: cpp
|
||||||
|
|
||||||
|
void do_something_with_example(std::unique_ptr<Example> ex) { ... }
|
||||||
|
|
||||||
|
The above signature would imply that Python needs to give up ownership of an
|
||||||
|
object that is passed to this function, which is generally not possible (for
|
||||||
|
instance, the object might be referenced elsewhere).
|
||||||
|
|
||||||
|
std::shared_ptr
|
||||||
|
===============
|
||||||
|
|
||||||
|
The binding generator for classes, :class:`class_`, can be passed a template
|
||||||
|
type that denotes a special *holder* type that is used to manage references to
|
||||||
|
the object. If no such holder type template argument is given, the default for
|
||||||
|
a type named ``Type`` is ``std::unique_ptr<Type>``, which means that the object
|
||||||
|
is deallocated when Python's reference count goes to zero.
|
||||||
|
|
||||||
|
It is possible to switch to other types of reference counting wrappers or smart
|
||||||
|
pointers, which is useful in codebases that rely on them. For instance, the
|
||||||
|
following snippet causes ``std::shared_ptr`` to be used instead.
|
||||||
|
|
||||||
|
.. code-block:: cpp
|
||||||
|
|
||||||
|
py::class_<Example, std::shared_ptr<Example> /* <- holder type */> obj(m, "Example");
|
||||||
|
|
||||||
|
Note that any particular class can only be associated with a single holder type.
|
||||||
|
|
||||||
|
One potential stumbling block when using holder types is that they need to be
|
||||||
|
applied consistently. Can you guess what's broken about the following binding
|
||||||
|
code?
|
||||||
|
|
||||||
|
.. code-block:: cpp
|
||||||
|
|
||||||
|
class Child { };
|
||||||
|
|
||||||
|
class Parent {
|
||||||
|
public:
|
||||||
|
Parent() : child(std::make_shared<Child>()) { }
|
||||||
|
Child *get_child() { return child.get(); } /* Hint: ** DON'T DO THIS ** */
|
||||||
|
private:
|
||||||
|
std::shared_ptr<Child> child;
|
||||||
|
};
|
||||||
|
|
||||||
|
PYBIND11_MODULE(example, m) {
|
||||||
|
py::class_<Child, std::shared_ptr<Child>>(m, "Child");
|
||||||
|
|
||||||
|
py::class_<Parent, std::shared_ptr<Parent>>(m, "Parent")
|
||||||
|
.def(py::init<>())
|
||||||
|
.def("get_child", &Parent::get_child);
|
||||||
|
}
|
||||||
|
|
||||||
|
The following Python code will cause undefined behavior (and likely a
|
||||||
|
segmentation fault).
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
from example import Parent
|
||||||
|
print(Parent().get_child())
|
||||||
|
|
||||||
|
The problem is that ``Parent::get_child()`` returns a pointer to an instance of
|
||||||
|
``Child``, but the fact that this instance is already managed by
|
||||||
|
``std::shared_ptr<...>`` is lost when passing raw pointers. In this case,
|
||||||
|
pybind11 will create a second independent ``std::shared_ptr<...>`` that also
|
||||||
|
claims ownership of the pointer. In the end, the object will be freed **twice**
|
||||||
|
since these shared pointers have no way of knowing about each other.
|
||||||
|
|
||||||
|
There are two ways to resolve this issue:
|
||||||
|
|
||||||
|
1. For types that are managed by a smart pointer class, never use raw pointers
|
||||||
|
in function arguments or return values. In other words: always consistently
|
||||||
|
wrap pointers into their designated holder types (such as
|
||||||
|
``std::shared_ptr<...>``). In this case, the signature of ``get_child()``
|
||||||
|
should be modified as follows:
|
||||||
|
|
||||||
|
.. code-block:: cpp
|
||||||
|
|
||||||
|
std::shared_ptr<Child> get_child() { return child; }
|
||||||
|
|
||||||
|
2. Adjust the definition of ``Child`` by specifying
|
||||||
|
``std::enable_shared_from_this<T>`` (see cppreference_ for details) as a
|
||||||
|
base class. This adds a small bit of information to ``Child`` that allows
|
||||||
|
pybind11 to realize that there is already an existing
|
||||||
|
``std::shared_ptr<...>`` and communicate with it. In this case, the
|
||||||
|
declaration of ``Child`` should look as follows:
|
||||||
|
|
||||||
|
.. _cppreference: http://en.cppreference.com/w/cpp/memory/enable_shared_from_this
|
||||||
|
|
||||||
|
.. code-block:: cpp
|
||||||
|
|
||||||
|
class Child : public std::enable_shared_from_this<Child> { };
|
||||||
|
|
||||||
|
.. _smart_pointers:
|
||||||
|
|
||||||
|
Custom smart pointers
|
||||||
|
=====================
|
||||||
|
|
||||||
|
pybind11 supports ``std::unique_ptr`` and ``std::shared_ptr`` right out of the
|
||||||
|
box. For any other custom smart pointer, transparent conversions can be enabled
|
||||||
|
using a macro invocation similar to the following. It must be declared at the
|
||||||
|
top namespace level before any binding code:
|
||||||
|
|
||||||
|
.. code-block:: cpp
|
||||||
|
|
||||||
|
PYBIND11_DECLARE_HOLDER_TYPE(T, SmartPtr<T>);
|
||||||
|
|
||||||
|
The first argument of :func:`PYBIND11_DECLARE_HOLDER_TYPE` should be a
|
||||||
|
placeholder name that is used as a template parameter of the second argument.
|
||||||
|
Thus, feel free to use any identifier, but use it consistently on both sides;
|
||||||
|
also, don't use the name of a type that already exists in your codebase.
|
||||||
|
|
||||||
|
The macro also accepts a third optional boolean parameter that is set to false
|
||||||
|
by default. Specify
|
||||||
|
|
||||||
|
.. code-block:: cpp
|
||||||
|
|
||||||
|
PYBIND11_DECLARE_HOLDER_TYPE(T, SmartPtr<T>, true);
|
||||||
|
|
||||||
|
if ``SmartPtr<T>`` can always be initialized from a ``T*`` pointer without the
|
||||||
|
risk of inconsistencies (such as multiple independent ``SmartPtr`` instances
|
||||||
|
believing that they are the sole owner of the ``T*`` pointer). A common
|
||||||
|
situation where ``true`` should be passed is when the ``T`` instances use
|
||||||
|
*intrusive* reference counting.
|
||||||
|
|
||||||
|
Please take a look at the :ref:`macro_notes` before using this feature.
|
||||||
|
|
||||||
|
By default, pybind11 assumes that your custom smart pointer has a standard
|
||||||
|
interface, i.e. provides a ``.get()`` member function to access the underlying
|
||||||
|
raw pointer. If this is not the case, pybind11's ``holder_helper`` must be
|
||||||
|
specialized:
|
||||||
|
|
||||||
|
.. code-block:: cpp
|
||||||
|
|
||||||
|
// Always needed for custom holder types
|
||||||
|
PYBIND11_DECLARE_HOLDER_TYPE(T, SmartPtr<T>);
|
||||||
|
|
||||||
|
// Only needed if the type's `.get()` goes by another name
|
||||||
|
namespace pybind11 { namespace detail {
|
||||||
|
template <typename T>
|
||||||
|
struct holder_helper<SmartPtr<T>> { // <-- specialization
|
||||||
|
static const T *get(const SmartPtr<T> &p) { return p.getPointer(); }
|
||||||
|
};
|
||||||
|
}}
|
||||||
|
|
||||||
|
The above specialization informs pybind11 that the custom ``SmartPtr`` class
|
||||||
|
provides ``.get()`` functionality via ``.getPointer()``.
|
||||||
|
|
||||||
|
.. seealso::
|
||||||
|
|
||||||
|
The file :file:`tests/test_smart_ptr.cpp` contains a complete example
|
||||||
|
that demonstrates how to work with custom reference-counting holder types
|
||||||
|
in more detail.
|
293
3rdparty/pybind11/docs/basics.rst
vendored
Normal file
293
3rdparty/pybind11/docs/basics.rst
vendored
Normal file
@ -0,0 +1,293 @@
|
|||||||
|
.. _basics:
|
||||||
|
|
||||||
|
First steps
|
||||||
|
###########
|
||||||
|
|
||||||
|
This sections demonstrates the basic features of pybind11. Before getting
|
||||||
|
started, make sure that development environment is set up to compile the
|
||||||
|
included set of test cases.
|
||||||
|
|
||||||
|
|
||||||
|
Compiling the test cases
|
||||||
|
========================
|
||||||
|
|
||||||
|
Linux/MacOS
|
||||||
|
-----------
|
||||||
|
|
||||||
|
On Linux you'll need to install the **python-dev** or **python3-dev** packages as
|
||||||
|
well as **cmake**. On Mac OS, the included python version works out of the box,
|
||||||
|
but **cmake** must still be installed.
|
||||||
|
|
||||||
|
After installing the prerequisites, run
|
||||||
|
|
||||||
|
.. code-block:: bash
|
||||||
|
|
||||||
|
mkdir build
|
||||||
|
cd build
|
||||||
|
cmake ..
|
||||||
|
make check -j 4
|
||||||
|
|
||||||
|
The last line will both compile and run the tests.
|
||||||
|
|
||||||
|
Windows
|
||||||
|
-------
|
||||||
|
|
||||||
|
On Windows, only **Visual Studio 2015** and newer are supported since pybind11 relies
|
||||||
|
on various C++11 language features that break older versions of Visual Studio.
|
||||||
|
|
||||||
|
To compile and run the tests:
|
||||||
|
|
||||||
|
.. code-block:: batch
|
||||||
|
|
||||||
|
mkdir build
|
||||||
|
cd build
|
||||||
|
cmake ..
|
||||||
|
cmake --build . --config Release --target check
|
||||||
|
|
||||||
|
This will create a Visual Studio project, compile and run the target, all from the
|
||||||
|
command line.
|
||||||
|
|
||||||
|
.. Note::
|
||||||
|
|
||||||
|
If all tests fail, make sure that the Python binary and the testcases are compiled
|
||||||
|
for the same processor type and bitness (i.e. either **i386** or **x86_64**). You
|
||||||
|
can specify **x86_64** as the target architecture for the generated Visual Studio
|
||||||
|
project using ``cmake -A x64 ..``.
|
||||||
|
|
||||||
|
.. seealso::
|
||||||
|
|
||||||
|
Advanced users who are already familiar with Boost.Python may want to skip
|
||||||
|
the tutorial and look at the test cases in the :file:`tests` directory,
|
||||||
|
which exercise all features of pybind11.
|
||||||
|
|
||||||
|
Header and namespace conventions
|
||||||
|
================================
|
||||||
|
|
||||||
|
For brevity, all code examples assume that the following two lines are present:
|
||||||
|
|
||||||
|
.. code-block:: cpp
|
||||||
|
|
||||||
|
#include <pybind11/pybind11.h>
|
||||||
|
|
||||||
|
namespace py = pybind11;
|
||||||
|
|
||||||
|
Some features may require additional headers, but those will be specified as needed.
|
||||||
|
|
||||||
|
.. _simple_example:
|
||||||
|
|
||||||
|
Creating bindings for a simple function
|
||||||
|
=======================================
|
||||||
|
|
||||||
|
Let's start by creating Python bindings for an extremely simple function, which
|
||||||
|
adds two numbers and returns their result:
|
||||||
|
|
||||||
|
.. code-block:: cpp
|
||||||
|
|
||||||
|
int add(int i, int j) {
|
||||||
|
return i + j;
|
||||||
|
}
|
||||||
|
|
||||||
|
For simplicity [#f1]_, we'll put both this function and the binding code into
|
||||||
|
a file named :file:`example.cpp` with the following contents:
|
||||||
|
|
||||||
|
.. code-block:: cpp
|
||||||
|
|
||||||
|
#include <pybind11/pybind11.h>
|
||||||
|
|
||||||
|
int add(int i, int j) {
|
||||||
|
return i + j;
|
||||||
|
}
|
||||||
|
|
||||||
|
PYBIND11_MODULE(example, m) {
|
||||||
|
m.doc() = "pybind11 example plugin"; // optional module docstring
|
||||||
|
|
||||||
|
m.def("add", &add, "A function which adds two numbers");
|
||||||
|
}
|
||||||
|
|
||||||
|
.. [#f1] In practice, implementation and binding code will generally be located
|
||||||
|
in separate files.
|
||||||
|
|
||||||
|
The :func:`PYBIND11_MODULE` macro creates a function that will be called when an
|
||||||
|
``import`` statement is issued from within Python. The module name (``example``)
|
||||||
|
is given as the first macro argument (it should not be in quotes). The second
|
||||||
|
argument (``m``) defines a variable of type :class:`py::module <module>` which
|
||||||
|
is the main interface for creating bindings. The method :func:`module::def`
|
||||||
|
generates binding code that exposes the ``add()`` function to Python.
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
|
||||||
|
Notice how little code was needed to expose our function to Python: all
|
||||||
|
details regarding the function's parameters and return value were
|
||||||
|
automatically inferred using template metaprogramming. This overall
|
||||||
|
approach and the used syntax are borrowed from Boost.Python, though the
|
||||||
|
underlying implementation is very different.
|
||||||
|
|
||||||
|
pybind11 is a header-only library, hence it is not necessary to link against
|
||||||
|
any special libraries and there are no intermediate (magic) translation steps.
|
||||||
|
On Linux, the above example can be compiled using the following command:
|
||||||
|
|
||||||
|
.. code-block:: bash
|
||||||
|
|
||||||
|
$ c++ -O3 -Wall -shared -std=c++11 -fPIC `python3 -m pybind11 --includes` example.cpp -o example`python3-config --extension-suffix`
|
||||||
|
|
||||||
|
For more details on the required compiler flags on Linux and MacOS, see
|
||||||
|
:ref:`building_manually`. For complete cross-platform compilation instructions,
|
||||||
|
refer to the :ref:`compiling` page.
|
||||||
|
|
||||||
|
The `python_example`_ and `cmake_example`_ repositories are also a good place
|
||||||
|
to start. They are both complete project examples with cross-platform build
|
||||||
|
systems. The only difference between the two is that `python_example`_ uses
|
||||||
|
Python's ``setuptools`` to build the module, while `cmake_example`_ uses CMake
|
||||||
|
(which may be preferable for existing C++ projects).
|
||||||
|
|
||||||
|
.. _python_example: https://github.com/pybind/python_example
|
||||||
|
.. _cmake_example: https://github.com/pybind/cmake_example
|
||||||
|
|
||||||
|
Building the above C++ code will produce a binary module file that can be
|
||||||
|
imported to Python. Assuming that the compiled module is located in the
|
||||||
|
current directory, the following interactive Python session shows how to
|
||||||
|
load and execute the example:
|
||||||
|
|
||||||
|
.. code-block:: pycon
|
||||||
|
|
||||||
|
$ python
|
||||||
|
Python 2.7.10 (default, Aug 22 2015, 20:33:39)
|
||||||
|
[GCC 4.2.1 Compatible Apple LLVM 7.0.0 (clang-700.0.59.1)] on darwin
|
||||||
|
Type "help", "copyright", "credits" or "license" for more information.
|
||||||
|
>>> import example
|
||||||
|
>>> example.add(1, 2)
|
||||||
|
3L
|
||||||
|
>>>
|
||||||
|
|
||||||
|
.. _keyword_args:
|
||||||
|
|
||||||
|
Keyword arguments
|
||||||
|
=================
|
||||||
|
|
||||||
|
With a simple code modification, it is possible to inform Python about the
|
||||||
|
names of the arguments ("i" and "j" in this case).
|
||||||
|
|
||||||
|
.. code-block:: cpp
|
||||||
|
|
||||||
|
m.def("add", &add, "A function which adds two numbers",
|
||||||
|
py::arg("i"), py::arg("j"));
|
||||||
|
|
||||||
|
:class:`arg` is one of several special tag classes which can be used to pass
|
||||||
|
metadata into :func:`module::def`. With this modified binding code, we can now
|
||||||
|
call the function using keyword arguments, which is a more readable alternative
|
||||||
|
particularly for functions taking many parameters:
|
||||||
|
|
||||||
|
.. code-block:: pycon
|
||||||
|
|
||||||
|
>>> import example
|
||||||
|
>>> example.add(i=1, j=2)
|
||||||
|
3L
|
||||||
|
|
||||||
|
The keyword names also appear in the function signatures within the documentation.
|
||||||
|
|
||||||
|
.. code-block:: pycon
|
||||||
|
|
||||||
|
>>> help(example)
|
||||||
|
|
||||||
|
....
|
||||||
|
|
||||||
|
FUNCTIONS
|
||||||
|
add(...)
|
||||||
|
Signature : (i: int, j: int) -> int
|
||||||
|
|
||||||
|
A function which adds two numbers
|
||||||
|
|
||||||
|
A shorter notation for named arguments is also available:
|
||||||
|
|
||||||
|
.. code-block:: cpp
|
||||||
|
|
||||||
|
// regular notation
|
||||||
|
m.def("add1", &add, py::arg("i"), py::arg("j"));
|
||||||
|
// shorthand
|
||||||
|
using namespace pybind11::literals;
|
||||||
|
m.def("add2", &add, "i"_a, "j"_a);
|
||||||
|
|
||||||
|
The :var:`_a` suffix forms a C++11 literal which is equivalent to :class:`arg`.
|
||||||
|
Note that the literal operator must first be made visible with the directive
|
||||||
|
``using namespace pybind11::literals``. This does not bring in anything else
|
||||||
|
from the ``pybind11`` namespace except for literals.
|
||||||
|
|
||||||
|
.. _default_args:
|
||||||
|
|
||||||
|
Default arguments
|
||||||
|
=================
|
||||||
|
|
||||||
|
Suppose now that the function to be bound has default arguments, e.g.:
|
||||||
|
|
||||||
|
.. code-block:: cpp
|
||||||
|
|
||||||
|
int add(int i = 1, int j = 2) {
|
||||||
|
return i + j;
|
||||||
|
}
|
||||||
|
|
||||||
|
Unfortunately, pybind11 cannot automatically extract these parameters, since they
|
||||||
|
are not part of the function's type information. However, they are simple to specify
|
||||||
|
using an extension of :class:`arg`:
|
||||||
|
|
||||||
|
.. code-block:: cpp
|
||||||
|
|
||||||
|
m.def("add", &add, "A function which adds two numbers",
|
||||||
|
py::arg("i") = 1, py::arg("j") = 2);
|
||||||
|
|
||||||
|
The default values also appear within the documentation.
|
||||||
|
|
||||||
|
.. code-block:: pycon
|
||||||
|
|
||||||
|
>>> help(example)
|
||||||
|
|
||||||
|
....
|
||||||
|
|
||||||
|
FUNCTIONS
|
||||||
|
add(...)
|
||||||
|
Signature : (i: int = 1, j: int = 2) -> int
|
||||||
|
|
||||||
|
A function which adds two numbers
|
||||||
|
|
||||||
|
The shorthand notation is also available for default arguments:
|
||||||
|
|
||||||
|
.. code-block:: cpp
|
||||||
|
|
||||||
|
// regular notation
|
||||||
|
m.def("add1", &add, py::arg("i") = 1, py::arg("j") = 2);
|
||||||
|
// shorthand
|
||||||
|
m.def("add2", &add, "i"_a=1, "j"_a=2);
|
||||||
|
|
||||||
|
Exporting variables
|
||||||
|
===================
|
||||||
|
|
||||||
|
To expose a value from C++, use the ``attr`` function to register it in a
|
||||||
|
module as shown below. Built-in types and general objects (more on that later)
|
||||||
|
are automatically converted when assigned as attributes, and can be explicitly
|
||||||
|
converted using the function ``py::cast``.
|
||||||
|
|
||||||
|
.. code-block:: cpp
|
||||||
|
|
||||||
|
PYBIND11_MODULE(example, m) {
|
||||||
|
m.attr("the_answer") = 42;
|
||||||
|
py::object world = py::cast("World");
|
||||||
|
m.attr("what") = world;
|
||||||
|
}
|
||||||
|
|
||||||
|
These are then accessible from Python:
|
||||||
|
|
||||||
|
.. code-block:: pycon
|
||||||
|
|
||||||
|
>>> import example
|
||||||
|
>>> example.the_answer
|
||||||
|
42
|
||||||
|
>>> example.what
|
||||||
|
'World'
|
||||||
|
|
||||||
|
.. _supported_types:
|
||||||
|
|
||||||
|
Supported data types
|
||||||
|
====================
|
||||||
|
|
||||||
|
A large number of data types are supported out of the box and can be used
|
||||||
|
seamlessly as functions arguments, return values or with ``py::cast`` in general.
|
||||||
|
For a full overview, see the :doc:`advanced/cast/index` section.
|
88
3rdparty/pybind11/docs/benchmark.py
vendored
Normal file
88
3rdparty/pybind11/docs/benchmark.py
vendored
Normal file
@ -0,0 +1,88 @@
|
|||||||
|
import random
|
||||||
|
import os
|
||||||
|
import time
|
||||||
|
import datetime as dt
|
||||||
|
|
||||||
|
nfns = 4 # Functions per class
|
||||||
|
nargs = 4 # Arguments per function
|
||||||
|
|
||||||
|
|
||||||
|
def generate_dummy_code_pybind11(nclasses=10):
|
||||||
|
decl = ""
|
||||||
|
bindings = ""
|
||||||
|
|
||||||
|
for cl in range(nclasses):
|
||||||
|
decl += "class cl%03i;\n" % cl
|
||||||
|
decl += '\n'
|
||||||
|
|
||||||
|
for cl in range(nclasses):
|
||||||
|
decl += "class cl%03i {\n" % cl
|
||||||
|
decl += "public:\n"
|
||||||
|
bindings += ' py::class_<cl%03i>(m, "cl%03i")\n' % (cl, cl)
|
||||||
|
for fn in range(nfns):
|
||||||
|
ret = random.randint(0, nclasses - 1)
|
||||||
|
params = [random.randint(0, nclasses - 1) for i in range(nargs)]
|
||||||
|
decl += " cl%03i *fn_%03i(" % (ret, fn)
|
||||||
|
decl += ", ".join("cl%03i *" % p for p in params)
|
||||||
|
decl += ");\n"
|
||||||
|
bindings += ' .def("fn_%03i", &cl%03i::fn_%03i)\n' % \
|
||||||
|
(fn, cl, fn)
|
||||||
|
decl += "};\n\n"
|
||||||
|
bindings += ' ;\n'
|
||||||
|
|
||||||
|
result = "#include <pybind11/pybind11.h>\n\n"
|
||||||
|
result += "namespace py = pybind11;\n\n"
|
||||||
|
result += decl + '\n'
|
||||||
|
result += "PYBIND11_MODULE(example, m) {\n"
|
||||||
|
result += bindings
|
||||||
|
result += "}"
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
def generate_dummy_code_boost(nclasses=10):
|
||||||
|
decl = ""
|
||||||
|
bindings = ""
|
||||||
|
|
||||||
|
for cl in range(nclasses):
|
||||||
|
decl += "class cl%03i;\n" % cl
|
||||||
|
decl += '\n'
|
||||||
|
|
||||||
|
for cl in range(nclasses):
|
||||||
|
decl += "class cl%03i {\n" % cl
|
||||||
|
decl += "public:\n"
|
||||||
|
bindings += ' py::class_<cl%03i>("cl%03i")\n' % (cl, cl)
|
||||||
|
for fn in range(nfns):
|
||||||
|
ret = random.randint(0, nclasses - 1)
|
||||||
|
params = [random.randint(0, nclasses - 1) for i in range(nargs)]
|
||||||
|
decl += " cl%03i *fn_%03i(" % (ret, fn)
|
||||||
|
decl += ", ".join("cl%03i *" % p for p in params)
|
||||||
|
decl += ");\n"
|
||||||
|
bindings += ' .def("fn_%03i", &cl%03i::fn_%03i, py::return_value_policy<py::manage_new_object>())\n' % \
|
||||||
|
(fn, cl, fn)
|
||||||
|
decl += "};\n\n"
|
||||||
|
bindings += ' ;\n'
|
||||||
|
|
||||||
|
result = "#include <boost/python.hpp>\n\n"
|
||||||
|
result += "namespace py = boost::python;\n\n"
|
||||||
|
result += decl + '\n'
|
||||||
|
result += "BOOST_PYTHON_MODULE(example) {\n"
|
||||||
|
result += bindings
|
||||||
|
result += "}"
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
for codegen in [generate_dummy_code_pybind11, generate_dummy_code_boost]:
|
||||||
|
print ("{")
|
||||||
|
for i in range(0, 10):
|
||||||
|
nclasses = 2 ** i
|
||||||
|
with open("test.cpp", "w") as f:
|
||||||
|
f.write(codegen(nclasses))
|
||||||
|
n1 = dt.datetime.now()
|
||||||
|
os.system("g++ -Os -shared -rdynamic -undefined dynamic_lookup "
|
||||||
|
"-fvisibility=hidden -std=c++14 test.cpp -I include "
|
||||||
|
"-I /System/Library/Frameworks/Python.framework/Headers -o test.so")
|
||||||
|
n2 = dt.datetime.now()
|
||||||
|
elapsed = (n2 - n1).total_seconds()
|
||||||
|
size = os.stat('test.so').st_size
|
||||||
|
print(" {%i, %f, %i}," % (nclasses * nfns, elapsed, size))
|
||||||
|
print ("}")
|
97
3rdparty/pybind11/docs/benchmark.rst
vendored
Normal file
97
3rdparty/pybind11/docs/benchmark.rst
vendored
Normal file
@ -0,0 +1,97 @@
|
|||||||
|
Benchmark
|
||||||
|
=========
|
||||||
|
|
||||||
|
The following is the result of a synthetic benchmark comparing both compilation
|
||||||
|
time and module size of pybind11 against Boost.Python. A detailed report about a
|
||||||
|
Boost.Python to pybind11 conversion of a real project is available here: [#f1]_.
|
||||||
|
|
||||||
|
.. [#f1] http://graylab.jhu.edu/RosettaCon2016/PyRosetta-4.pdf
|
||||||
|
|
||||||
|
Setup
|
||||||
|
-----
|
||||||
|
|
||||||
|
A python script (see the ``docs/benchmark.py`` file) was used to generate a set
|
||||||
|
of files with dummy classes whose count increases for each successive benchmark
|
||||||
|
(between 1 and 2048 classes in powers of two). Each class has four methods with
|
||||||
|
a randomly generated signature with a return value and four arguments. (There
|
||||||
|
was no particular reason for this setup other than the desire to generate many
|
||||||
|
unique function signatures whose count could be controlled in a simple way.)
|
||||||
|
|
||||||
|
Here is an example of the binding code for one class:
|
||||||
|
|
||||||
|
.. code-block:: cpp
|
||||||
|
|
||||||
|
...
|
||||||
|
class cl034 {
|
||||||
|
public:
|
||||||
|
cl279 *fn_000(cl084 *, cl057 *, cl065 *, cl042 *);
|
||||||
|
cl025 *fn_001(cl098 *, cl262 *, cl414 *, cl121 *);
|
||||||
|
cl085 *fn_002(cl445 *, cl297 *, cl145 *, cl421 *);
|
||||||
|
cl470 *fn_003(cl200 *, cl323 *, cl332 *, cl492 *);
|
||||||
|
};
|
||||||
|
...
|
||||||
|
|
||||||
|
PYBIND11_MODULE(example, m) {
|
||||||
|
...
|
||||||
|
py::class_<cl034>(m, "cl034")
|
||||||
|
.def("fn_000", &cl034::fn_000)
|
||||||
|
.def("fn_001", &cl034::fn_001)
|
||||||
|
.def("fn_002", &cl034::fn_002)
|
||||||
|
.def("fn_003", &cl034::fn_003)
|
||||||
|
...
|
||||||
|
}
|
||||||
|
|
||||||
|
The Boost.Python version looks almost identical except that a return value
|
||||||
|
policy had to be specified as an argument to ``def()``. For both libraries,
|
||||||
|
compilation was done with
|
||||||
|
|
||||||
|
.. code-block:: bash
|
||||||
|
|
||||||
|
Apple LLVM version 7.0.2 (clang-700.1.81)
|
||||||
|
|
||||||
|
and the following compilation flags
|
||||||
|
|
||||||
|
.. code-block:: bash
|
||||||
|
|
||||||
|
g++ -Os -shared -rdynamic -undefined dynamic_lookup -fvisibility=hidden -std=c++14
|
||||||
|
|
||||||
|
Compilation time
|
||||||
|
----------------
|
||||||
|
|
||||||
|
The following log-log plot shows how the compilation time grows for an
|
||||||
|
increasing number of class and function declarations. pybind11 includes many
|
||||||
|
fewer headers, which initially leads to shorter compilation times, but the
|
||||||
|
performance is ultimately fairly similar (pybind11 is 19.8 seconds faster for
|
||||||
|
the largest largest file with 2048 classes and a total of 8192 methods -- a
|
||||||
|
modest **1.2x** speedup relative to Boost.Python, which required 116.35
|
||||||
|
seconds).
|
||||||
|
|
||||||
|
.. only:: not latex
|
||||||
|
|
||||||
|
.. image:: pybind11_vs_boost_python1.svg
|
||||||
|
|
||||||
|
.. only:: latex
|
||||||
|
|
||||||
|
.. image:: pybind11_vs_boost_python1.png
|
||||||
|
|
||||||
|
Module size
|
||||||
|
-----------
|
||||||
|
|
||||||
|
Differences between the two libraries become much more pronounced when
|
||||||
|
considering the file size of the generated Python plugin: for the largest file,
|
||||||
|
the binary generated by Boost.Python required 16.8 MiB, which was **2.17
|
||||||
|
times** / **9.1 megabytes** larger than the output generated by pybind11. For
|
||||||
|
very small inputs, Boost.Python has an edge in the plot below -- however, note
|
||||||
|
that it stores many definitions in an external library, whose size was not
|
||||||
|
included here, hence the comparison is slightly shifted in Boost.Python's
|
||||||
|
favor.
|
||||||
|
|
||||||
|
.. only:: not latex
|
||||||
|
|
||||||
|
.. image:: pybind11_vs_boost_python2.svg
|
||||||
|
|
||||||
|
.. only:: latex
|
||||||
|
|
||||||
|
.. image:: pybind11_vs_boost_python2.png
|
||||||
|
|
||||||
|
|
1277
3rdparty/pybind11/docs/changelog.rst
vendored
Normal file
1277
3rdparty/pybind11/docs/changelog.rst
vendored
Normal file
File diff suppressed because it is too large
Load Diff
532
3rdparty/pybind11/docs/classes.rst
vendored
Normal file
532
3rdparty/pybind11/docs/classes.rst
vendored
Normal file
@ -0,0 +1,532 @@
|
|||||||
|
.. _classes:
|
||||||
|
|
||||||
|
Object-oriented code
|
||||||
|
####################
|
||||||
|
|
||||||
|
Creating bindings for a custom type
|
||||||
|
===================================
|
||||||
|
|
||||||
|
Let's now look at a more complex example where we'll create bindings for a
|
||||||
|
custom C++ data structure named ``Pet``. Its definition is given below:
|
||||||
|
|
||||||
|
.. code-block:: cpp
|
||||||
|
|
||||||
|
struct Pet {
|
||||||
|
Pet(const std::string &name) : name(name) { }
|
||||||
|
void setName(const std::string &name_) { name = name_; }
|
||||||
|
const std::string &getName() const { return name; }
|
||||||
|
|
||||||
|
std::string name;
|
||||||
|
};
|
||||||
|
|
||||||
|
The binding code for ``Pet`` looks as follows:
|
||||||
|
|
||||||
|
.. code-block:: cpp
|
||||||
|
|
||||||
|
#include <pybind11/pybind11.h>
|
||||||
|
|
||||||
|
namespace py = pybind11;
|
||||||
|
|
||||||
|
PYBIND11_MODULE(example, m) {
|
||||||
|
py::class_<Pet>(m, "Pet")
|
||||||
|
.def(py::init<const std::string &>())
|
||||||
|
.def("setName", &Pet::setName)
|
||||||
|
.def("getName", &Pet::getName);
|
||||||
|
}
|
||||||
|
|
||||||
|
:class:`class_` creates bindings for a C++ *class* or *struct*-style data
|
||||||
|
structure. :func:`init` is a convenience function that takes the types of a
|
||||||
|
constructor's parameters as template arguments and wraps the corresponding
|
||||||
|
constructor (see the :ref:`custom_constructors` section for details). An
|
||||||
|
interactive Python session demonstrating this example is shown below:
|
||||||
|
|
||||||
|
.. code-block:: pycon
|
||||||
|
|
||||||
|
% python
|
||||||
|
>>> import example
|
||||||
|
>>> p = example.Pet('Molly')
|
||||||
|
>>> print(p)
|
||||||
|
<example.Pet object at 0x10cd98060>
|
||||||
|
>>> p.getName()
|
||||||
|
u'Molly'
|
||||||
|
>>> p.setName('Charly')
|
||||||
|
>>> p.getName()
|
||||||
|
u'Charly'
|
||||||
|
|
||||||
|
.. seealso::
|
||||||
|
|
||||||
|
Static member functions can be bound in the same way using
|
||||||
|
:func:`class_::def_static`.
|
||||||
|
|
||||||
|
Keyword and default arguments
|
||||||
|
=============================
|
||||||
|
It is possible to specify keyword and default arguments using the syntax
|
||||||
|
discussed in the previous chapter. Refer to the sections :ref:`keyword_args`
|
||||||
|
and :ref:`default_args` for details.
|
||||||
|
|
||||||
|
Binding lambda functions
|
||||||
|
========================
|
||||||
|
|
||||||
|
Note how ``print(p)`` produced a rather useless summary of our data structure in the example above:
|
||||||
|
|
||||||
|
.. code-block:: pycon
|
||||||
|
|
||||||
|
>>> print(p)
|
||||||
|
<example.Pet object at 0x10cd98060>
|
||||||
|
|
||||||
|
To address this, we could bind an utility function that returns a human-readable
|
||||||
|
summary to the special method slot named ``__repr__``. Unfortunately, there is no
|
||||||
|
suitable functionality in the ``Pet`` data structure, and it would be nice if
|
||||||
|
we did not have to change it. This can easily be accomplished by binding a
|
||||||
|
Lambda function instead:
|
||||||
|
|
||||||
|
.. code-block:: cpp
|
||||||
|
|
||||||
|
py::class_<Pet>(m, "Pet")
|
||||||
|
.def(py::init<const std::string &>())
|
||||||
|
.def("setName", &Pet::setName)
|
||||||
|
.def("getName", &Pet::getName)
|
||||||
|
.def("__repr__",
|
||||||
|
[](const Pet &a) {
|
||||||
|
return "<example.Pet named '" + a.name + "'>";
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
Both stateless [#f1]_ and stateful lambda closures are supported by pybind11.
|
||||||
|
With the above change, the same Python code now produces the following output:
|
||||||
|
|
||||||
|
.. code-block:: pycon
|
||||||
|
|
||||||
|
>>> print(p)
|
||||||
|
<example.Pet named 'Molly'>
|
||||||
|
|
||||||
|
.. [#f1] Stateless closures are those with an empty pair of brackets ``[]`` as the capture object.
|
||||||
|
|
||||||
|
.. _properties:
|
||||||
|
|
||||||
|
Instance and static fields
|
||||||
|
==========================
|
||||||
|
|
||||||
|
We can also directly expose the ``name`` field using the
|
||||||
|
:func:`class_::def_readwrite` method. A similar :func:`class_::def_readonly`
|
||||||
|
method also exists for ``const`` fields.
|
||||||
|
|
||||||
|
.. code-block:: cpp
|
||||||
|
|
||||||
|
py::class_<Pet>(m, "Pet")
|
||||||
|
.def(py::init<const std::string &>())
|
||||||
|
.def_readwrite("name", &Pet::name)
|
||||||
|
// ... remainder ...
|
||||||
|
|
||||||
|
This makes it possible to write
|
||||||
|
|
||||||
|
.. code-block:: pycon
|
||||||
|
|
||||||
|
>>> p = example.Pet('Molly')
|
||||||
|
>>> p.name
|
||||||
|
u'Molly'
|
||||||
|
>>> p.name = 'Charly'
|
||||||
|
>>> p.name
|
||||||
|
u'Charly'
|
||||||
|
|
||||||
|
Now suppose that ``Pet::name`` was a private internal variable
|
||||||
|
that can only be accessed via setters and getters.
|
||||||
|
|
||||||
|
.. code-block:: cpp
|
||||||
|
|
||||||
|
class Pet {
|
||||||
|
public:
|
||||||
|
Pet(const std::string &name) : name(name) { }
|
||||||
|
void setName(const std::string &name_) { name = name_; }
|
||||||
|
const std::string &getName() const { return name; }
|
||||||
|
private:
|
||||||
|
std::string name;
|
||||||
|
};
|
||||||
|
|
||||||
|
In this case, the method :func:`class_::def_property`
|
||||||
|
(:func:`class_::def_property_readonly` for read-only data) can be used to
|
||||||
|
provide a field-like interface within Python that will transparently call
|
||||||
|
the setter and getter functions:
|
||||||
|
|
||||||
|
.. code-block:: cpp
|
||||||
|
|
||||||
|
py::class_<Pet>(m, "Pet")
|
||||||
|
.def(py::init<const std::string &>())
|
||||||
|
.def_property("name", &Pet::getName, &Pet::setName)
|
||||||
|
// ... remainder ...
|
||||||
|
|
||||||
|
Write only properties can be defined by passing ``nullptr`` as the
|
||||||
|
input for the read function.
|
||||||
|
|
||||||
|
.. seealso::
|
||||||
|
|
||||||
|
Similar functions :func:`class_::def_readwrite_static`,
|
||||||
|
:func:`class_::def_readonly_static` :func:`class_::def_property_static`,
|
||||||
|
and :func:`class_::def_property_readonly_static` are provided for binding
|
||||||
|
static variables and properties. Please also see the section on
|
||||||
|
:ref:`static_properties` in the advanced part of the documentation.
|
||||||
|
|
||||||
|
Dynamic attributes
|
||||||
|
==================
|
||||||
|
|
||||||
|
Native Python classes can pick up new attributes dynamically:
|
||||||
|
|
||||||
|
.. code-block:: pycon
|
||||||
|
|
||||||
|
>>> class Pet:
|
||||||
|
... name = 'Molly'
|
||||||
|
...
|
||||||
|
>>> p = Pet()
|
||||||
|
>>> p.name = 'Charly' # overwrite existing
|
||||||
|
>>> p.age = 2 # dynamically add a new attribute
|
||||||
|
|
||||||
|
By default, classes exported from C++ do not support this and the only writable
|
||||||
|
attributes are the ones explicitly defined using :func:`class_::def_readwrite`
|
||||||
|
or :func:`class_::def_property`.
|
||||||
|
|
||||||
|
.. code-block:: cpp
|
||||||
|
|
||||||
|
py::class_<Pet>(m, "Pet")
|
||||||
|
.def(py::init<>())
|
||||||
|
.def_readwrite("name", &Pet::name);
|
||||||
|
|
||||||
|
Trying to set any other attribute results in an error:
|
||||||
|
|
||||||
|
.. code-block:: pycon
|
||||||
|
|
||||||
|
>>> p = example.Pet()
|
||||||
|
>>> p.name = 'Charly' # OK, attribute defined in C++
|
||||||
|
>>> p.age = 2 # fail
|
||||||
|
AttributeError: 'Pet' object has no attribute 'age'
|
||||||
|
|
||||||
|
To enable dynamic attributes for C++ classes, the :class:`py::dynamic_attr` tag
|
||||||
|
must be added to the :class:`py::class_` constructor:
|
||||||
|
|
||||||
|
.. code-block:: cpp
|
||||||
|
|
||||||
|
py::class_<Pet>(m, "Pet", py::dynamic_attr())
|
||||||
|
.def(py::init<>())
|
||||||
|
.def_readwrite("name", &Pet::name);
|
||||||
|
|
||||||
|
Now everything works as expected:
|
||||||
|
|
||||||
|
.. code-block:: pycon
|
||||||
|
|
||||||
|
>>> p = example.Pet()
|
||||||
|
>>> p.name = 'Charly' # OK, overwrite value in C++
|
||||||
|
>>> p.age = 2 # OK, dynamically add a new attribute
|
||||||
|
>>> p.__dict__ # just like a native Python class
|
||||||
|
{'age': 2}
|
||||||
|
|
||||||
|
Note that there is a small runtime cost for a class with dynamic attributes.
|
||||||
|
Not only because of the addition of a ``__dict__``, but also because of more
|
||||||
|
expensive garbage collection tracking which must be activated to resolve
|
||||||
|
possible circular references. Native Python classes incur this same cost by
|
||||||
|
default, so this is not anything to worry about. By default, pybind11 classes
|
||||||
|
are more efficient than native Python classes. Enabling dynamic attributes
|
||||||
|
just brings them on par.
|
||||||
|
|
||||||
|
.. _inheritance:
|
||||||
|
|
||||||
|
Inheritance and automatic downcasting
|
||||||
|
=====================================
|
||||||
|
|
||||||
|
Suppose now that the example consists of two data structures with an
|
||||||
|
inheritance relationship:
|
||||||
|
|
||||||
|
.. code-block:: cpp
|
||||||
|
|
||||||
|
struct Pet {
|
||||||
|
Pet(const std::string &name) : name(name) { }
|
||||||
|
std::string name;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Dog : Pet {
|
||||||
|
Dog(const std::string &name) : Pet(name) { }
|
||||||
|
std::string bark() const { return "woof!"; }
|
||||||
|
};
|
||||||
|
|
||||||
|
There are two different ways of indicating a hierarchical relationship to
|
||||||
|
pybind11: the first specifies the C++ base class as an extra template
|
||||||
|
parameter of the :class:`class_`:
|
||||||
|
|
||||||
|
.. code-block:: cpp
|
||||||
|
|
||||||
|
py::class_<Pet>(m, "Pet")
|
||||||
|
.def(py::init<const std::string &>())
|
||||||
|
.def_readwrite("name", &Pet::name);
|
||||||
|
|
||||||
|
// Method 1: template parameter:
|
||||||
|
py::class_<Dog, Pet /* <- specify C++ parent type */>(m, "Dog")
|
||||||
|
.def(py::init<const std::string &>())
|
||||||
|
.def("bark", &Dog::bark);
|
||||||
|
|
||||||
|
Alternatively, we can also assign a name to the previously bound ``Pet``
|
||||||
|
:class:`class_` object and reference it when binding the ``Dog`` class:
|
||||||
|
|
||||||
|
.. code-block:: cpp
|
||||||
|
|
||||||
|
py::class_<Pet> pet(m, "Pet");
|
||||||
|
pet.def(py::init<const std::string &>())
|
||||||
|
.def_readwrite("name", &Pet::name);
|
||||||
|
|
||||||
|
// Method 2: pass parent class_ object:
|
||||||
|
py::class_<Dog>(m, "Dog", pet /* <- specify Python parent type */)
|
||||||
|
.def(py::init<const std::string &>())
|
||||||
|
.def("bark", &Dog::bark);
|
||||||
|
|
||||||
|
Functionality-wise, both approaches are equivalent. Afterwards, instances will
|
||||||
|
expose fields and methods of both types:
|
||||||
|
|
||||||
|
.. code-block:: pycon
|
||||||
|
|
||||||
|
>>> p = example.Dog('Molly')
|
||||||
|
>>> p.name
|
||||||
|
u'Molly'
|
||||||
|
>>> p.bark()
|
||||||
|
u'woof!'
|
||||||
|
|
||||||
|
The C++ classes defined above are regular non-polymorphic types with an
|
||||||
|
inheritance relationship. This is reflected in Python:
|
||||||
|
|
||||||
|
.. code-block:: cpp
|
||||||
|
|
||||||
|
// Return a base pointer to a derived instance
|
||||||
|
m.def("pet_store", []() { return std::unique_ptr<Pet>(new Dog("Molly")); });
|
||||||
|
|
||||||
|
.. code-block:: pycon
|
||||||
|
|
||||||
|
>>> p = example.pet_store()
|
||||||
|
>>> type(p) # `Dog` instance behind `Pet` pointer
|
||||||
|
Pet # no pointer downcasting for regular non-polymorphic types
|
||||||
|
>>> p.bark()
|
||||||
|
AttributeError: 'Pet' object has no attribute 'bark'
|
||||||
|
|
||||||
|
The function returned a ``Dog`` instance, but because it's a non-polymorphic
|
||||||
|
type behind a base pointer, Python only sees a ``Pet``. In C++, a type is only
|
||||||
|
considered polymorphic if it has at least one virtual function and pybind11
|
||||||
|
will automatically recognize this:
|
||||||
|
|
||||||
|
.. code-block:: cpp
|
||||||
|
|
||||||
|
struct PolymorphicPet {
|
||||||
|
virtual ~PolymorphicPet() = default;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct PolymorphicDog : PolymorphicPet {
|
||||||
|
std::string bark() const { return "woof!"; }
|
||||||
|
};
|
||||||
|
|
||||||
|
// Same binding code
|
||||||
|
py::class_<PolymorphicPet>(m, "PolymorphicPet");
|
||||||
|
py::class_<PolymorphicDog, PolymorphicPet>(m, "PolymorphicDog")
|
||||||
|
.def(py::init<>())
|
||||||
|
.def("bark", &PolymorphicDog::bark);
|
||||||
|
|
||||||
|
// Again, return a base pointer to a derived instance
|
||||||
|
m.def("pet_store2", []() { return std::unique_ptr<PolymorphicPet>(new PolymorphicDog); });
|
||||||
|
|
||||||
|
.. code-block:: pycon
|
||||||
|
|
||||||
|
>>> p = example.pet_store2()
|
||||||
|
>>> type(p)
|
||||||
|
PolymorphicDog # automatically downcast
|
||||||
|
>>> p.bark()
|
||||||
|
u'woof!'
|
||||||
|
|
||||||
|
Given a pointer to a polymorphic base, pybind11 performs automatic downcasting
|
||||||
|
to the actual derived type. Note that this goes beyond the usual situation in
|
||||||
|
C++: we don't just get access to the virtual functions of the base, we get the
|
||||||
|
concrete derived type including functions and attributes that the base type may
|
||||||
|
not even be aware of.
|
||||||
|
|
||||||
|
.. seealso::
|
||||||
|
|
||||||
|
For more information about polymorphic behavior see :ref:`overriding_virtuals`.
|
||||||
|
|
||||||
|
|
||||||
|
Overloaded methods
|
||||||
|
==================
|
||||||
|
|
||||||
|
Sometimes there are several overloaded C++ methods with the same name taking
|
||||||
|
different kinds of input arguments:
|
||||||
|
|
||||||
|
.. code-block:: cpp
|
||||||
|
|
||||||
|
struct Pet {
|
||||||
|
Pet(const std::string &name, int age) : name(name), age(age) { }
|
||||||
|
|
||||||
|
void set(int age_) { age = age_; }
|
||||||
|
void set(const std::string &name_) { name = name_; }
|
||||||
|
|
||||||
|
std::string name;
|
||||||
|
int age;
|
||||||
|
};
|
||||||
|
|
||||||
|
Attempting to bind ``Pet::set`` will cause an error since the compiler does not
|
||||||
|
know which method the user intended to select. We can disambiguate by casting
|
||||||
|
them to function pointers. Binding multiple functions to the same Python name
|
||||||
|
automatically creates a chain of function overloads that will be tried in
|
||||||
|
sequence.
|
||||||
|
|
||||||
|
.. code-block:: cpp
|
||||||
|
|
||||||
|
py::class_<Pet>(m, "Pet")
|
||||||
|
.def(py::init<const std::string &, int>())
|
||||||
|
.def("set", (void (Pet::*)(int)) &Pet::set, "Set the pet's age")
|
||||||
|
.def("set", (void (Pet::*)(const std::string &)) &Pet::set, "Set the pet's name");
|
||||||
|
|
||||||
|
The overload signatures are also visible in the method's docstring:
|
||||||
|
|
||||||
|
.. code-block:: pycon
|
||||||
|
|
||||||
|
>>> help(example.Pet)
|
||||||
|
|
||||||
|
class Pet(__builtin__.object)
|
||||||
|
| Methods defined here:
|
||||||
|
|
|
||||||
|
| __init__(...)
|
||||||
|
| Signature : (Pet, str, int) -> NoneType
|
||||||
|
|
|
||||||
|
| set(...)
|
||||||
|
| 1. Signature : (Pet, int) -> NoneType
|
||||||
|
|
|
||||||
|
| Set the pet's age
|
||||||
|
|
|
||||||
|
| 2. Signature : (Pet, str) -> NoneType
|
||||||
|
|
|
||||||
|
| Set the pet's name
|
||||||
|
|
||||||
|
If you have a C++14 compatible compiler [#cpp14]_, you can use an alternative
|
||||||
|
syntax to cast the overloaded function:
|
||||||
|
|
||||||
|
.. code-block:: cpp
|
||||||
|
|
||||||
|
py::class_<Pet>(m, "Pet")
|
||||||
|
.def("set", py::overload_cast<int>(&Pet::set), "Set the pet's age")
|
||||||
|
.def("set", py::overload_cast<const std::string &>(&Pet::set), "Set the pet's name");
|
||||||
|
|
||||||
|
Here, ``py::overload_cast`` only requires the parameter types to be specified.
|
||||||
|
The return type and class are deduced. This avoids the additional noise of
|
||||||
|
``void (Pet::*)()`` as seen in the raw cast. If a function is overloaded based
|
||||||
|
on constness, the ``py::const_`` tag should be used:
|
||||||
|
|
||||||
|
.. code-block:: cpp
|
||||||
|
|
||||||
|
struct Widget {
|
||||||
|
int foo(int x, float y);
|
||||||
|
int foo(int x, float y) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
py::class_<Widget>(m, "Widget")
|
||||||
|
.def("foo_mutable", py::overload_cast<int, float>(&Widget::foo))
|
||||||
|
.def("foo_const", py::overload_cast<int, float>(&Widget::foo, py::const_));
|
||||||
|
|
||||||
|
If you prefer the ``py::overload_cast`` syntax but have a C++11 compatible compiler only,
|
||||||
|
you can use ``py::detail::overload_cast_impl`` with an additional set of parentheses:
|
||||||
|
|
||||||
|
.. code-block:: cpp
|
||||||
|
|
||||||
|
template <typename... Args>
|
||||||
|
using overload_cast_ = pybind11::detail::overload_cast_impl<Args...>;
|
||||||
|
|
||||||
|
py::class_<Pet>(m, "Pet")
|
||||||
|
.def("set", overload_cast_<int>()(&Pet::set), "Set the pet's age")
|
||||||
|
.def("set", overload_cast_<const std::string &>()(&Pet::set), "Set the pet's name");
|
||||||
|
|
||||||
|
.. [#cpp14] A compiler which supports the ``-std=c++14`` flag
|
||||||
|
or Visual Studio 2015 Update 2 and newer.
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
|
||||||
|
To define multiple overloaded constructors, simply declare one after the
|
||||||
|
other using the ``.def(py::init<...>())`` syntax. The existing machinery
|
||||||
|
for specifying keyword and default arguments also works.
|
||||||
|
|
||||||
|
Enumerations and internal types
|
||||||
|
===============================
|
||||||
|
|
||||||
|
Let's now suppose that the example class contains an internal enumeration type,
|
||||||
|
e.g.:
|
||||||
|
|
||||||
|
.. code-block:: cpp
|
||||||
|
|
||||||
|
struct Pet {
|
||||||
|
enum Kind {
|
||||||
|
Dog = 0,
|
||||||
|
Cat
|
||||||
|
};
|
||||||
|
|
||||||
|
Pet(const std::string &name, Kind type) : name(name), type(type) { }
|
||||||
|
|
||||||
|
std::string name;
|
||||||
|
Kind type;
|
||||||
|
};
|
||||||
|
|
||||||
|
The binding code for this example looks as follows:
|
||||||
|
|
||||||
|
.. code-block:: cpp
|
||||||
|
|
||||||
|
py::class_<Pet> pet(m, "Pet");
|
||||||
|
|
||||||
|
pet.def(py::init<const std::string &, Pet::Kind>())
|
||||||
|
.def_readwrite("name", &Pet::name)
|
||||||
|
.def_readwrite("type", &Pet::type);
|
||||||
|
|
||||||
|
py::enum_<Pet::Kind>(pet, "Kind")
|
||||||
|
.value("Dog", Pet::Kind::Dog)
|
||||||
|
.value("Cat", Pet::Kind::Cat)
|
||||||
|
.export_values();
|
||||||
|
|
||||||
|
To ensure that the ``Kind`` type is created within the scope of ``Pet``, the
|
||||||
|
``pet`` :class:`class_` instance must be supplied to the :class:`enum_`.
|
||||||
|
constructor. The :func:`enum_::export_values` function exports the enum entries
|
||||||
|
into the parent scope, which should be skipped for newer C++11-style strongly
|
||||||
|
typed enums.
|
||||||
|
|
||||||
|
.. code-block:: pycon
|
||||||
|
|
||||||
|
>>> p = Pet('Lucy', Pet.Cat)
|
||||||
|
>>> p.type
|
||||||
|
Kind.Cat
|
||||||
|
>>> int(p.type)
|
||||||
|
1L
|
||||||
|
|
||||||
|
The entries defined by the enumeration type are exposed in the ``__members__`` property:
|
||||||
|
|
||||||
|
.. code-block:: pycon
|
||||||
|
|
||||||
|
>>> Pet.Kind.__members__
|
||||||
|
{'Dog': Kind.Dog, 'Cat': Kind.Cat}
|
||||||
|
|
||||||
|
The ``name`` property returns the name of the enum value as a unicode string.
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
|
||||||
|
It is also possible to use ``str(enum)``, however these accomplish different
|
||||||
|
goals. The following shows how these two approaches differ.
|
||||||
|
|
||||||
|
.. code-block:: pycon
|
||||||
|
|
||||||
|
>>> p = Pet( "Lucy", Pet.Cat )
|
||||||
|
>>> pet_type = p.type
|
||||||
|
>>> pet_type
|
||||||
|
Pet.Cat
|
||||||
|
>>> str(pet_type)
|
||||||
|
'Pet.Cat'
|
||||||
|
>>> pet_type.name
|
||||||
|
'Cat'
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
|
||||||
|
When the special tag ``py::arithmetic()`` is specified to the ``enum_``
|
||||||
|
constructor, pybind11 creates an enumeration that also supports rudimentary
|
||||||
|
arithmetic and bit-level operations like comparisons, and, or, xor, negation,
|
||||||
|
etc.
|
||||||
|
|
||||||
|
.. code-block:: cpp
|
||||||
|
|
||||||
|
py::enum_<Pet::Kind>(pet, "Kind", py::arithmetic())
|
||||||
|
...
|
||||||
|
|
||||||
|
By default, these are omitted to conserve space.
|
289
3rdparty/pybind11/docs/compiling.rst
vendored
Normal file
289
3rdparty/pybind11/docs/compiling.rst
vendored
Normal file
@ -0,0 +1,289 @@
|
|||||||
|
.. _compiling:
|
||||||
|
|
||||||
|
Build systems
|
||||||
|
#############
|
||||||
|
|
||||||
|
Building with setuptools
|
||||||
|
========================
|
||||||
|
|
||||||
|
For projects on PyPI, building with setuptools is the way to go. Sylvain Corlay
|
||||||
|
has kindly provided an example project which shows how to set up everything,
|
||||||
|
including automatic generation of documentation using Sphinx. Please refer to
|
||||||
|
the [python_example]_ repository.
|
||||||
|
|
||||||
|
.. [python_example] https://github.com/pybind/python_example
|
||||||
|
|
||||||
|
Building with cppimport
|
||||||
|
========================
|
||||||
|
|
||||||
|
[cppimport]_ is a small Python import hook that determines whether there is a C++
|
||||||
|
source file whose name matches the requested module. If there is, the file is
|
||||||
|
compiled as a Python extension using pybind11 and placed in the same folder as
|
||||||
|
the C++ source file. Python is then able to find the module and load it.
|
||||||
|
|
||||||
|
.. [cppimport] https://github.com/tbenthompson/cppimport
|
||||||
|
|
||||||
|
.. _cmake:
|
||||||
|
|
||||||
|
Building with CMake
|
||||||
|
===================
|
||||||
|
|
||||||
|
For C++ codebases that have an existing CMake-based build system, a Python
|
||||||
|
extension module can be created with just a few lines of code:
|
||||||
|
|
||||||
|
.. code-block:: cmake
|
||||||
|
|
||||||
|
cmake_minimum_required(VERSION 2.8.12)
|
||||||
|
project(example)
|
||||||
|
|
||||||
|
add_subdirectory(pybind11)
|
||||||
|
pybind11_add_module(example example.cpp)
|
||||||
|
|
||||||
|
This assumes that the pybind11 repository is located in a subdirectory named
|
||||||
|
:file:`pybind11` and that the code is located in a file named :file:`example.cpp`.
|
||||||
|
The CMake command ``add_subdirectory`` will import the pybind11 project which
|
||||||
|
provides the ``pybind11_add_module`` function. It will take care of all the
|
||||||
|
details needed to build a Python extension module on any platform.
|
||||||
|
|
||||||
|
A working sample project, including a way to invoke CMake from :file:`setup.py` for
|
||||||
|
PyPI integration, can be found in the [cmake_example]_ repository.
|
||||||
|
|
||||||
|
.. [cmake_example] https://github.com/pybind/cmake_example
|
||||||
|
|
||||||
|
pybind11_add_module
|
||||||
|
-------------------
|
||||||
|
|
||||||
|
To ease the creation of Python extension modules, pybind11 provides a CMake
|
||||||
|
function with the following signature:
|
||||||
|
|
||||||
|
.. code-block:: cmake
|
||||||
|
|
||||||
|
pybind11_add_module(<name> [MODULE | SHARED] [EXCLUDE_FROM_ALL]
|
||||||
|
[NO_EXTRAS] [SYSTEM] [THIN_LTO] source1 [source2 ...])
|
||||||
|
|
||||||
|
This function behaves very much like CMake's builtin ``add_library`` (in fact,
|
||||||
|
it's a wrapper function around that command). It will add a library target
|
||||||
|
called ``<name>`` to be built from the listed source files. In addition, it
|
||||||
|
will take care of all the Python-specific compiler and linker flags as well
|
||||||
|
as the OS- and Python-version-specific file extension. The produced target
|
||||||
|
``<name>`` can be further manipulated with regular CMake commands.
|
||||||
|
|
||||||
|
``MODULE`` or ``SHARED`` may be given to specify the type of library. If no
|
||||||
|
type is given, ``MODULE`` is used by default which ensures the creation of a
|
||||||
|
Python-exclusive module. Specifying ``SHARED`` will create a more traditional
|
||||||
|
dynamic library which can also be linked from elsewhere. ``EXCLUDE_FROM_ALL``
|
||||||
|
removes this target from the default build (see CMake docs for details).
|
||||||
|
|
||||||
|
Since pybind11 is a template library, ``pybind11_add_module`` adds compiler
|
||||||
|
flags to ensure high quality code generation without bloat arising from long
|
||||||
|
symbol names and duplication of code in different translation units. It
|
||||||
|
sets default visibility to *hidden*, which is required for some pybind11
|
||||||
|
features and functionality when attempting to load multiple pybind11 modules
|
||||||
|
compiled under different pybind11 versions. It also adds additional flags
|
||||||
|
enabling LTO (Link Time Optimization) and strip unneeded symbols. See the
|
||||||
|
:ref:`FAQ entry <faq:symhidden>` for a more detailed explanation. These
|
||||||
|
latter optimizations are never applied in ``Debug`` mode. If ``NO_EXTRAS`` is
|
||||||
|
given, they will always be disabled, even in ``Release`` mode. However, this
|
||||||
|
will result in code bloat and is generally not recommended.
|
||||||
|
|
||||||
|
By default, pybind11 and Python headers will be included with ``-I``. In order
|
||||||
|
to include pybind11 as system library, e.g. to avoid warnings in downstream
|
||||||
|
code with warn-levels outside of pybind11's scope, set the option ``SYSTEM``.
|
||||||
|
|
||||||
|
As stated above, LTO is enabled by default. Some newer compilers also support
|
||||||
|
different flavors of LTO such as `ThinLTO`_. Setting ``THIN_LTO`` will cause
|
||||||
|
the function to prefer this flavor if available. The function falls back to
|
||||||
|
regular LTO if ``-flto=thin`` is not available.
|
||||||
|
|
||||||
|
.. _ThinLTO: http://clang.llvm.org/docs/ThinLTO.html
|
||||||
|
|
||||||
|
Configuration variables
|
||||||
|
-----------------------
|
||||||
|
|
||||||
|
By default, pybind11 will compile modules with the C++14 standard, if available
|
||||||
|
on the target compiler, falling back to C++11 if C++14 support is not
|
||||||
|
available. Note, however, that this default is subject to change: future
|
||||||
|
pybind11 releases are expected to migrate to newer C++ standards as they become
|
||||||
|
available. To override this, the standard flag can be given explicitly in
|
||||||
|
``PYBIND11_CPP_STANDARD``:
|
||||||
|
|
||||||
|
.. code-block:: cmake
|
||||||
|
|
||||||
|
# Use just one of these:
|
||||||
|
# GCC/clang:
|
||||||
|
set(PYBIND11_CPP_STANDARD -std=c++11)
|
||||||
|
set(PYBIND11_CPP_STANDARD -std=c++14)
|
||||||
|
set(PYBIND11_CPP_STANDARD -std=c++1z) # Experimental C++17 support
|
||||||
|
# MSVC:
|
||||||
|
set(PYBIND11_CPP_STANDARD /std:c++14)
|
||||||
|
set(PYBIND11_CPP_STANDARD /std:c++latest) # Enables some MSVC C++17 features
|
||||||
|
|
||||||
|
add_subdirectory(pybind11) # or find_package(pybind11)
|
||||||
|
|
||||||
|
Note that this and all other configuration variables must be set **before** the
|
||||||
|
call to ``add_subdirectory`` or ``find_package``. The variables can also be set
|
||||||
|
when calling CMake from the command line using the ``-D<variable>=<value>`` flag.
|
||||||
|
|
||||||
|
The target Python version can be selected by setting ``PYBIND11_PYTHON_VERSION``
|
||||||
|
or an exact Python installation can be specified with ``PYTHON_EXECUTABLE``.
|
||||||
|
For example:
|
||||||
|
|
||||||
|
.. code-block:: bash
|
||||||
|
|
||||||
|
cmake -DPYBIND11_PYTHON_VERSION=3.6 ..
|
||||||
|
# or
|
||||||
|
cmake -DPYTHON_EXECUTABLE=path/to/python ..
|
||||||
|
|
||||||
|
find_package vs. add_subdirectory
|
||||||
|
---------------------------------
|
||||||
|
|
||||||
|
For CMake-based projects that don't include the pybind11 repository internally,
|
||||||
|
an external installation can be detected through ``find_package(pybind11)``.
|
||||||
|
See the `Config file`_ docstring for details of relevant CMake variables.
|
||||||
|
|
||||||
|
.. code-block:: cmake
|
||||||
|
|
||||||
|
cmake_minimum_required(VERSION 2.8.12)
|
||||||
|
project(example)
|
||||||
|
|
||||||
|
find_package(pybind11 REQUIRED)
|
||||||
|
pybind11_add_module(example example.cpp)
|
||||||
|
|
||||||
|
Note that ``find_package(pybind11)`` will only work correctly if pybind11
|
||||||
|
has been correctly installed on the system, e. g. after downloading or cloning
|
||||||
|
the pybind11 repository :
|
||||||
|
|
||||||
|
.. code-block:: bash
|
||||||
|
|
||||||
|
cd pybind11
|
||||||
|
mkdir build
|
||||||
|
cd build
|
||||||
|
cmake ..
|
||||||
|
make install
|
||||||
|
|
||||||
|
Once detected, the aforementioned ``pybind11_add_module`` can be employed as
|
||||||
|
before. The function usage and configuration variables are identical no matter
|
||||||
|
if pybind11 is added as a subdirectory or found as an installed package. You
|
||||||
|
can refer to the same [cmake_example]_ repository for a full sample project
|
||||||
|
-- just swap out ``add_subdirectory`` for ``find_package``.
|
||||||
|
|
||||||
|
.. _Config file: https://github.com/pybind/pybind11/blob/master/tools/pybind11Config.cmake.in
|
||||||
|
|
||||||
|
Advanced: interface library target
|
||||||
|
----------------------------------
|
||||||
|
|
||||||
|
When using a version of CMake greater than 3.0, pybind11 can additionally
|
||||||
|
be used as a special *interface library* . The target ``pybind11::module``
|
||||||
|
is available with pybind11 headers, Python headers and libraries as needed,
|
||||||
|
and C++ compile definitions attached. This target is suitable for linking
|
||||||
|
to an independently constructed (through ``add_library``, not
|
||||||
|
``pybind11_add_module``) target in the consuming project.
|
||||||
|
|
||||||
|
.. code-block:: cmake
|
||||||
|
|
||||||
|
cmake_minimum_required(VERSION 3.0)
|
||||||
|
project(example)
|
||||||
|
|
||||||
|
find_package(pybind11 REQUIRED) # or add_subdirectory(pybind11)
|
||||||
|
|
||||||
|
add_library(example MODULE main.cpp)
|
||||||
|
target_link_libraries(example PRIVATE pybind11::module)
|
||||||
|
set_target_properties(example PROPERTIES PREFIX "${PYTHON_MODULE_PREFIX}"
|
||||||
|
SUFFIX "${PYTHON_MODULE_EXTENSION}")
|
||||||
|
|
||||||
|
.. warning::
|
||||||
|
|
||||||
|
Since pybind11 is a metatemplate library, it is crucial that certain
|
||||||
|
compiler flags are provided to ensure high quality code generation. In
|
||||||
|
contrast to the ``pybind11_add_module()`` command, the CMake interface
|
||||||
|
library only provides the *minimal* set of parameters to ensure that the
|
||||||
|
code using pybind11 compiles, but it does **not** pass these extra compiler
|
||||||
|
flags (i.e. this is up to you).
|
||||||
|
|
||||||
|
These include Link Time Optimization (``-flto`` on GCC/Clang/ICPC, ``/GL``
|
||||||
|
and ``/LTCG`` on Visual Studio) and .OBJ files with many sections on Visual
|
||||||
|
Studio (``/bigobj``). The :ref:`FAQ <faq:symhidden>` contains an
|
||||||
|
explanation on why these are needed.
|
||||||
|
|
||||||
|
Embedding the Python interpreter
|
||||||
|
--------------------------------
|
||||||
|
|
||||||
|
In addition to extension modules, pybind11 also supports embedding Python into
|
||||||
|
a C++ executable or library. In CMake, simply link with the ``pybind11::embed``
|
||||||
|
target. It provides everything needed to get the interpreter running. The Python
|
||||||
|
headers and libraries are attached to the target. Unlike ``pybind11::module``,
|
||||||
|
there is no need to manually set any additional properties here. For more
|
||||||
|
information about usage in C++, see :doc:`/advanced/embedding`.
|
||||||
|
|
||||||
|
.. code-block:: cmake
|
||||||
|
|
||||||
|
cmake_minimum_required(VERSION 3.0)
|
||||||
|
project(example)
|
||||||
|
|
||||||
|
find_package(pybind11 REQUIRED) # or add_subdirectory(pybind11)
|
||||||
|
|
||||||
|
add_executable(example main.cpp)
|
||||||
|
target_link_libraries(example PRIVATE pybind11::embed)
|
||||||
|
|
||||||
|
.. _building_manually:
|
||||||
|
|
||||||
|
Building manually
|
||||||
|
=================
|
||||||
|
|
||||||
|
pybind11 is a header-only library, hence it is not necessary to link against
|
||||||
|
any special libraries and there are no intermediate (magic) translation steps.
|
||||||
|
|
||||||
|
On Linux, you can compile an example such as the one given in
|
||||||
|
:ref:`simple_example` using the following command:
|
||||||
|
|
||||||
|
.. code-block:: bash
|
||||||
|
|
||||||
|
$ c++ -O3 -Wall -shared -std=c++11 -fPIC `python3 -m pybind11 --includes` example.cpp -o example`python3-config --extension-suffix`
|
||||||
|
|
||||||
|
The flags given here assume that you're using Python 3. For Python 2, just
|
||||||
|
change the executable appropriately (to ``python`` or ``python2``).
|
||||||
|
|
||||||
|
The ``python3 -m pybind11 --includes`` command fetches the include paths for
|
||||||
|
both pybind11 and Python headers. This assumes that pybind11 has been installed
|
||||||
|
using ``pip`` or ``conda``. If it hasn't, you can also manually specify
|
||||||
|
``-I <path-to-pybind11>/include`` together with the Python includes path
|
||||||
|
``python3-config --includes``.
|
||||||
|
|
||||||
|
Note that Python 2.7 modules don't use a special suffix, so you should simply
|
||||||
|
use ``example.so`` instead of ``example`python3-config --extension-suffix```.
|
||||||
|
Besides, the ``--extension-suffix`` option may or may not be available, depending
|
||||||
|
on the distribution; in the latter case, the module extension can be manually
|
||||||
|
set to ``.so``.
|
||||||
|
|
||||||
|
On Mac OS: the build command is almost the same but it also requires passing
|
||||||
|
the ``-undefined dynamic_lookup`` flag so as to ignore missing symbols when
|
||||||
|
building the module:
|
||||||
|
|
||||||
|
.. code-block:: bash
|
||||||
|
|
||||||
|
$ c++ -O3 -Wall -shared -std=c++11 -undefined dynamic_lookup `python3 -m pybind11 --includes` example.cpp -o example`python3-config --extension-suffix`
|
||||||
|
|
||||||
|
In general, it is advisable to include several additional build parameters
|
||||||
|
that can considerably reduce the size of the created binary. Refer to section
|
||||||
|
:ref:`cmake` for a detailed example of a suitable cross-platform CMake-based
|
||||||
|
build system that works on all platforms including Windows.
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
|
||||||
|
On Linux and macOS, it's better to (intentionally) not link against
|
||||||
|
``libpython``. The symbols will be resolved when the extension library
|
||||||
|
is loaded into a Python binary. This is preferable because you might
|
||||||
|
have several different installations of a given Python version (e.g. the
|
||||||
|
system-provided Python, and one that ships with a piece of commercial
|
||||||
|
software). In this way, the plugin will work with both versions, instead
|
||||||
|
of possibly importing a second Python library into a process that already
|
||||||
|
contains one (which will lead to a segfault).
|
||||||
|
|
||||||
|
Generating binding code automatically
|
||||||
|
=====================================
|
||||||
|
|
||||||
|
The ``Binder`` project is a tool for automatic generation of pybind11 binding
|
||||||
|
code by introspecting existing C++ codebases using LLVM/Clang. See the
|
||||||
|
[binder]_ documentation for details.
|
||||||
|
|
||||||
|
.. [binder] http://cppbinder.readthedocs.io/en/latest/about.html
|
332
3rdparty/pybind11/docs/conf.py
vendored
Normal file
332
3rdparty/pybind11/docs/conf.py
vendored
Normal file
@ -0,0 +1,332 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
#
|
||||||
|
# pybind11 documentation build configuration file, created by
|
||||||
|
# sphinx-quickstart on Sun Oct 11 19:23:48 2015.
|
||||||
|
#
|
||||||
|
# This file is execfile()d with the current directory set to its
|
||||||
|
# containing dir.
|
||||||
|
#
|
||||||
|
# Note that not all possible configuration values are present in this
|
||||||
|
# autogenerated file.
|
||||||
|
#
|
||||||
|
# All configuration values have a default; values that are commented out
|
||||||
|
# serve to show the default.
|
||||||
|
|
||||||
|
import sys
|
||||||
|
import os
|
||||||
|
import shlex
|
||||||
|
import subprocess
|
||||||
|
|
||||||
|
# If extensions (or modules to document with autodoc) are in another directory,
|
||||||
|
# add these directories to sys.path here. If the directory is relative to the
|
||||||
|
# documentation root, use os.path.abspath to make it absolute, like shown here.
|
||||||
|
#sys.path.insert(0, os.path.abspath('.'))
|
||||||
|
|
||||||
|
# -- General configuration ------------------------------------------------
|
||||||
|
|
||||||
|
# If your documentation needs a minimal Sphinx version, state it here.
|
||||||
|
#needs_sphinx = '1.0'
|
||||||
|
|
||||||
|
# Add any Sphinx extension module names here, as strings. They can be
|
||||||
|
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
|
||||||
|
# ones.
|
||||||
|
extensions = ['breathe']
|
||||||
|
|
||||||
|
breathe_projects = {'pybind11': '.build/doxygenxml/'}
|
||||||
|
breathe_default_project = 'pybind11'
|
||||||
|
breathe_domain_by_extension = {'h': 'cpp'}
|
||||||
|
|
||||||
|
# Add any paths that contain templates here, relative to this directory.
|
||||||
|
templates_path = ['.templates']
|
||||||
|
|
||||||
|
# The suffix(es) of source filenames.
|
||||||
|
# You can specify multiple suffix as a list of string:
|
||||||
|
# source_suffix = ['.rst', '.md']
|
||||||
|
source_suffix = '.rst'
|
||||||
|
|
||||||
|
# The encoding of source files.
|
||||||
|
#source_encoding = 'utf-8-sig'
|
||||||
|
|
||||||
|
# The master toctree document.
|
||||||
|
master_doc = 'index'
|
||||||
|
|
||||||
|
# General information about the project.
|
||||||
|
project = 'pybind11'
|
||||||
|
copyright = '2017, Wenzel Jakob'
|
||||||
|
author = 'Wenzel Jakob'
|
||||||
|
|
||||||
|
# The version info for the project you're documenting, acts as replacement for
|
||||||
|
# |version| and |release|, also used in various other places throughout the
|
||||||
|
# built documents.
|
||||||
|
#
|
||||||
|
# The short X.Y version.
|
||||||
|
version = '2.5'
|
||||||
|
# The full version, including alpha/beta/rc tags.
|
||||||
|
release = '2.5.0'
|
||||||
|
|
||||||
|
# The language for content autogenerated by Sphinx. Refer to documentation
|
||||||
|
# for a list of supported languages.
|
||||||
|
#
|
||||||
|
# This is also used if you do content translation via gettext catalogs.
|
||||||
|
# Usually you set "language" from the command line for these cases.
|
||||||
|
language = None
|
||||||
|
|
||||||
|
# There are two options for replacing |today|: either, you set today to some
|
||||||
|
# non-false value, then it is used:
|
||||||
|
#today = ''
|
||||||
|
# Else, today_fmt is used as the format for a strftime call.
|
||||||
|
#today_fmt = '%B %d, %Y'
|
||||||
|
|
||||||
|
# List of patterns, relative to source directory, that match files and
|
||||||
|
# directories to ignore when looking for source files.
|
||||||
|
exclude_patterns = ['.build', 'release.rst']
|
||||||
|
|
||||||
|
# The reST default role (used for this markup: `text`) to use for all
|
||||||
|
# documents.
|
||||||
|
default_role = 'any'
|
||||||
|
|
||||||
|
# If true, '()' will be appended to :func: etc. cross-reference text.
|
||||||
|
#add_function_parentheses = True
|
||||||
|
|
||||||
|
# If true, the current module name will be prepended to all description
|
||||||
|
# unit titles (such as .. function::).
|
||||||
|
#add_module_names = True
|
||||||
|
|
||||||
|
# If true, sectionauthor and moduleauthor directives will be shown in the
|
||||||
|
# output. They are ignored by default.
|
||||||
|
#show_authors = False
|
||||||
|
|
||||||
|
# The name of the Pygments (syntax highlighting) style to use.
|
||||||
|
#pygments_style = 'monokai'
|
||||||
|
|
||||||
|
# A list of ignored prefixes for module index sorting.
|
||||||
|
#modindex_common_prefix = []
|
||||||
|
|
||||||
|
# If true, keep warnings as "system message" paragraphs in the built documents.
|
||||||
|
#keep_warnings = False
|
||||||
|
|
||||||
|
# If true, `todo` and `todoList` produce output, else they produce nothing.
|
||||||
|
todo_include_todos = False
|
||||||
|
|
||||||
|
|
||||||
|
# -- Options for HTML output ----------------------------------------------
|
||||||
|
|
||||||
|
# The theme to use for HTML and HTML Help pages. See the documentation for
|
||||||
|
# a list of builtin themes.
|
||||||
|
|
||||||
|
on_rtd = os.environ.get('READTHEDOCS', None) == 'True'
|
||||||
|
|
||||||
|
if not on_rtd: # only import and set the theme if we're building docs locally
|
||||||
|
import sphinx_rtd_theme
|
||||||
|
html_theme = 'sphinx_rtd_theme'
|
||||||
|
html_theme_path = [sphinx_rtd_theme.get_html_theme_path()]
|
||||||
|
|
||||||
|
html_context = {
|
||||||
|
'css_files': [
|
||||||
|
'_static/theme_overrides.css'
|
||||||
|
]
|
||||||
|
}
|
||||||
|
else:
|
||||||
|
html_context = {
|
||||||
|
'css_files': [
|
||||||
|
'//media.readthedocs.org/css/sphinx_rtd_theme.css',
|
||||||
|
'//media.readthedocs.org/css/readthedocs-doc-embed.css',
|
||||||
|
'_static/theme_overrides.css'
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
# Theme options are theme-specific and customize the look and feel of a theme
|
||||||
|
# further. For a list of options available for each theme, see the
|
||||||
|
# documentation.
|
||||||
|
#html_theme_options = {}
|
||||||
|
|
||||||
|
# Add any paths that contain custom themes here, relative to this directory.
|
||||||
|
#html_theme_path = []
|
||||||
|
|
||||||
|
# The name for this set of Sphinx documents. If None, it defaults to
|
||||||
|
# "<project> v<release> documentation".
|
||||||
|
#html_title = None
|
||||||
|
|
||||||
|
# A shorter title for the navigation bar. Default is the same as html_title.
|
||||||
|
#html_short_title = None
|
||||||
|
|
||||||
|
# The name of an image file (relative to this directory) to place at the top
|
||||||
|
# of the sidebar.
|
||||||
|
#html_logo = None
|
||||||
|
|
||||||
|
# The name of an image file (within the static path) to use as favicon of the
|
||||||
|
# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
|
||||||
|
# pixels large.
|
||||||
|
#html_favicon = None
|
||||||
|
|
||||||
|
# Add any paths that contain custom static files (such as style sheets) here,
|
||||||
|
# relative to this directory. They are copied after the builtin static files,
|
||||||
|
# so a file named "default.css" will overwrite the builtin "default.css".
|
||||||
|
html_static_path = ['_static']
|
||||||
|
|
||||||
|
# Add any extra paths that contain custom files (such as robots.txt or
|
||||||
|
# .htaccess) here, relative to this directory. These files are copied
|
||||||
|
# directly to the root of the documentation.
|
||||||
|
#html_extra_path = []
|
||||||
|
|
||||||
|
# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
|
||||||
|
# using the given strftime format.
|
||||||
|
#html_last_updated_fmt = '%b %d, %Y'
|
||||||
|
|
||||||
|
# If true, SmartyPants will be used to convert quotes and dashes to
|
||||||
|
# typographically correct entities.
|
||||||
|
#html_use_smartypants = True
|
||||||
|
|
||||||
|
# Custom sidebar templates, maps document names to template names.
|
||||||
|
#html_sidebars = {}
|
||||||
|
|
||||||
|
# Additional templates that should be rendered to pages, maps page names to
|
||||||
|
# template names.
|
||||||
|
#html_additional_pages = {}
|
||||||
|
|
||||||
|
# If false, no module index is generated.
|
||||||
|
#html_domain_indices = True
|
||||||
|
|
||||||
|
# If false, no index is generated.
|
||||||
|
#html_use_index = True
|
||||||
|
|
||||||
|
# If true, the index is split into individual pages for each letter.
|
||||||
|
#html_split_index = False
|
||||||
|
|
||||||
|
# If true, links to the reST sources are added to the pages.
|
||||||
|
#html_show_sourcelink = True
|
||||||
|
|
||||||
|
# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
|
||||||
|
#html_show_sphinx = True
|
||||||
|
|
||||||
|
# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
|
||||||
|
#html_show_copyright = True
|
||||||
|
|
||||||
|
# If true, an OpenSearch description file will be output, and all pages will
|
||||||
|
# contain a <link> tag referring to it. The value of this option must be the
|
||||||
|
# base URL from which the finished HTML is served.
|
||||||
|
#html_use_opensearch = ''
|
||||||
|
|
||||||
|
# This is the file name suffix for HTML files (e.g. ".xhtml").
|
||||||
|
#html_file_suffix = None
|
||||||
|
|
||||||
|
# Language to be used for generating the HTML full-text search index.
|
||||||
|
# Sphinx supports the following languages:
|
||||||
|
# 'da', 'de', 'en', 'es', 'fi', 'fr', 'h', 'it', 'ja'
|
||||||
|
# 'nl', 'no', 'pt', 'ro', 'r', 'sv', 'tr'
|
||||||
|
#html_search_language = 'en'
|
||||||
|
|
||||||
|
# A dictionary with options for the search language support, empty by default.
|
||||||
|
# Now only 'ja' uses this config value
|
||||||
|
#html_search_options = {'type': 'default'}
|
||||||
|
|
||||||
|
# The name of a javascript file (relative to the configuration directory) that
|
||||||
|
# implements a search results scorer. If empty, the default will be used.
|
||||||
|
#html_search_scorer = 'scorer.js'
|
||||||
|
|
||||||
|
# Output file base name for HTML help builder.
|
||||||
|
htmlhelp_basename = 'pybind11doc'
|
||||||
|
|
||||||
|
# -- Options for LaTeX output ---------------------------------------------
|
||||||
|
|
||||||
|
latex_elements = {
|
||||||
|
# The paper size ('letterpaper' or 'a4paper').
|
||||||
|
#'papersize': 'letterpaper',
|
||||||
|
|
||||||
|
# The font size ('10pt', '11pt' or '12pt').
|
||||||
|
#'pointsize': '10pt',
|
||||||
|
|
||||||
|
# Additional stuff for the LaTeX preamble.
|
||||||
|
'preamble': '\DeclareUnicodeCharacter{00A0}{}',
|
||||||
|
|
||||||
|
# Latex figure (float) alignment
|
||||||
|
#'figure_align': 'htbp',
|
||||||
|
}
|
||||||
|
|
||||||
|
# Grouping the document tree into LaTeX files. List of tuples
|
||||||
|
# (source start file, target name, title,
|
||||||
|
# author, documentclass [howto, manual, or own class]).
|
||||||
|
latex_documents = [
|
||||||
|
(master_doc, 'pybind11.tex', 'pybind11 Documentation',
|
||||||
|
'Wenzel Jakob', 'manual'),
|
||||||
|
]
|
||||||
|
|
||||||
|
# The name of an image file (relative to this directory) to place at the top of
|
||||||
|
# the title page.
|
||||||
|
# latex_logo = 'pybind11-logo.png'
|
||||||
|
|
||||||
|
# For "manual" documents, if this is true, then toplevel headings are parts,
|
||||||
|
# not chapters.
|
||||||
|
#latex_use_parts = False
|
||||||
|
|
||||||
|
# If true, show page references after internal links.
|
||||||
|
#latex_show_pagerefs = False
|
||||||
|
|
||||||
|
# If true, show URL addresses after external links.
|
||||||
|
#latex_show_urls = False
|
||||||
|
|
||||||
|
# Documents to append as an appendix to all manuals.
|
||||||
|
#latex_appendices = []
|
||||||
|
|
||||||
|
# If false, no module index is generated.
|
||||||
|
#latex_domain_indices = True
|
||||||
|
|
||||||
|
|
||||||
|
# -- Options for manual page output ---------------------------------------
|
||||||
|
|
||||||
|
# One entry per manual page. List of tuples
|
||||||
|
# (source start file, name, description, authors, manual section).
|
||||||
|
man_pages = [
|
||||||
|
(master_doc, 'pybind11', 'pybind11 Documentation',
|
||||||
|
[author], 1)
|
||||||
|
]
|
||||||
|
|
||||||
|
# If true, show URL addresses after external links.
|
||||||
|
#man_show_urls = False
|
||||||
|
|
||||||
|
|
||||||
|
# -- Options for Texinfo output -------------------------------------------
|
||||||
|
|
||||||
|
# Grouping the document tree into Texinfo files. List of tuples
|
||||||
|
# (source start file, target name, title, author,
|
||||||
|
# dir menu entry, description, category)
|
||||||
|
texinfo_documents = [
|
||||||
|
(master_doc, 'pybind11', 'pybind11 Documentation',
|
||||||
|
author, 'pybind11', 'One line description of project.',
|
||||||
|
'Miscellaneous'),
|
||||||
|
]
|
||||||
|
|
||||||
|
# Documents to append as an appendix to all manuals.
|
||||||
|
#texinfo_appendices = []
|
||||||
|
|
||||||
|
# If false, no module index is generated.
|
||||||
|
#texinfo_domain_indices = True
|
||||||
|
|
||||||
|
# How to display URL addresses: 'footnote', 'no', or 'inline'.
|
||||||
|
#texinfo_show_urls = 'footnote'
|
||||||
|
|
||||||
|
# If true, do not generate a @detailmenu in the "Top" node's menu.
|
||||||
|
#texinfo_no_detailmenu = False
|
||||||
|
|
||||||
|
primary_domain = 'cpp'
|
||||||
|
highlight_language = 'cpp'
|
||||||
|
|
||||||
|
|
||||||
|
def generate_doxygen_xml(app):
|
||||||
|
build_dir = os.path.join(app.confdir, '.build')
|
||||||
|
if not os.path.exists(build_dir):
|
||||||
|
os.mkdir(build_dir)
|
||||||
|
|
||||||
|
try:
|
||||||
|
subprocess.call(['doxygen', '--version'])
|
||||||
|
retcode = subprocess.call(['doxygen'], cwd=app.confdir)
|
||||||
|
if retcode < 0:
|
||||||
|
sys.stderr.write("doxygen error code: {}\n".format(-retcode))
|
||||||
|
except OSError as e:
|
||||||
|
sys.stderr.write("doxygen execution failed: {}\n".format(e))
|
||||||
|
|
||||||
|
|
||||||
|
def setup(app):
|
||||||
|
"""Add hook for building doxygen xml when needed"""
|
||||||
|
app.connect("builder-inited", generate_doxygen_xml)
|
324
3rdparty/pybind11/docs/faq.rst
vendored
Normal file
324
3rdparty/pybind11/docs/faq.rst
vendored
Normal file
@ -0,0 +1,324 @@
|
|||||||
|
Frequently asked questions
|
||||||
|
##########################
|
||||||
|
|
||||||
|
"ImportError: dynamic module does not define init function"
|
||||||
|
===========================================================
|
||||||
|
|
||||||
|
1. Make sure that the name specified in PYBIND11_MODULE is identical to the
|
||||||
|
filename of the extension library (without prefixes such as .so)
|
||||||
|
|
||||||
|
2. If the above did not fix the issue, you are likely using an incompatible
|
||||||
|
version of Python (for instance, the extension library was compiled against
|
||||||
|
Python 2, while the interpreter is running on top of some version of Python
|
||||||
|
3, or vice versa).
|
||||||
|
|
||||||
|
"Symbol not found: ``__Py_ZeroStruct`` / ``_PyInstanceMethod_Type``"
|
||||||
|
========================================================================
|
||||||
|
|
||||||
|
See the first answer.
|
||||||
|
|
||||||
|
"SystemError: dynamic module not initialized properly"
|
||||||
|
======================================================
|
||||||
|
|
||||||
|
See the first answer.
|
||||||
|
|
||||||
|
The Python interpreter immediately crashes when importing my module
|
||||||
|
===================================================================
|
||||||
|
|
||||||
|
See the first answer.
|
||||||
|
|
||||||
|
CMake doesn't detect the right Python version
|
||||||
|
=============================================
|
||||||
|
|
||||||
|
The CMake-based build system will try to automatically detect the installed
|
||||||
|
version of Python and link against that. When this fails, or when there are
|
||||||
|
multiple versions of Python and it finds the wrong one, delete
|
||||||
|
``CMakeCache.txt`` and then invoke CMake as follows:
|
||||||
|
|
||||||
|
.. code-block:: bash
|
||||||
|
|
||||||
|
cmake -DPYTHON_EXECUTABLE:FILEPATH=<path-to-python-executable> .
|
||||||
|
|
||||||
|
.. _faq_reference_arguments:
|
||||||
|
|
||||||
|
Limitations involving reference arguments
|
||||||
|
=========================================
|
||||||
|
|
||||||
|
In C++, it's fairly common to pass arguments using mutable references or
|
||||||
|
mutable pointers, which allows both read and write access to the value
|
||||||
|
supplied by the caller. This is sometimes done for efficiency reasons, or to
|
||||||
|
realize functions that have multiple return values. Here are two very basic
|
||||||
|
examples:
|
||||||
|
|
||||||
|
.. code-block:: cpp
|
||||||
|
|
||||||
|
void increment(int &i) { i++; }
|
||||||
|
void increment_ptr(int *i) { (*i)++; }
|
||||||
|
|
||||||
|
In Python, all arguments are passed by reference, so there is no general
|
||||||
|
issue in binding such code from Python.
|
||||||
|
|
||||||
|
However, certain basic Python types (like ``str``, ``int``, ``bool``,
|
||||||
|
``float``, etc.) are **immutable**. This means that the following attempt
|
||||||
|
to port the function to Python doesn't have the same effect on the value
|
||||||
|
provided by the caller -- in fact, it does nothing at all.
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
def increment(i):
|
||||||
|
i += 1 # nope..
|
||||||
|
|
||||||
|
pybind11 is also affected by such language-level conventions, which means that
|
||||||
|
binding ``increment`` or ``increment_ptr`` will also create Python functions
|
||||||
|
that don't modify their arguments.
|
||||||
|
|
||||||
|
Although inconvenient, one workaround is to encapsulate the immutable types in
|
||||||
|
a custom type that does allow modifications.
|
||||||
|
|
||||||
|
An other alternative involves binding a small wrapper lambda function that
|
||||||
|
returns a tuple with all output arguments (see the remainder of the
|
||||||
|
documentation for examples on binding lambda functions). An example:
|
||||||
|
|
||||||
|
.. code-block:: cpp
|
||||||
|
|
||||||
|
int foo(int &i) { i++; return 123; }
|
||||||
|
|
||||||
|
and the binding code
|
||||||
|
|
||||||
|
.. code-block:: cpp
|
||||||
|
|
||||||
|
m.def("foo", [](int i) { int rv = foo(i); return std::make_tuple(rv, i); });
|
||||||
|
|
||||||
|
|
||||||
|
How can I reduce the build time?
|
||||||
|
================================
|
||||||
|
|
||||||
|
It's good practice to split binding code over multiple files, as in the
|
||||||
|
following example:
|
||||||
|
|
||||||
|
:file:`example.cpp`:
|
||||||
|
|
||||||
|
.. code-block:: cpp
|
||||||
|
|
||||||
|
void init_ex1(py::module &);
|
||||||
|
void init_ex2(py::module &);
|
||||||
|
/* ... */
|
||||||
|
|
||||||
|
PYBIND11_MODULE(example, m) {
|
||||||
|
init_ex1(m);
|
||||||
|
init_ex2(m);
|
||||||
|
/* ... */
|
||||||
|
}
|
||||||
|
|
||||||
|
:file:`ex1.cpp`:
|
||||||
|
|
||||||
|
.. code-block:: cpp
|
||||||
|
|
||||||
|
void init_ex1(py::module &m) {
|
||||||
|
m.def("add", [](int a, int b) { return a + b; });
|
||||||
|
}
|
||||||
|
|
||||||
|
:file:`ex2.cpp`:
|
||||||
|
|
||||||
|
.. code-block:: cpp
|
||||||
|
|
||||||
|
void init_ex2(py::module &m) {
|
||||||
|
m.def("sub", [](int a, int b) { return a - b; });
|
||||||
|
}
|
||||||
|
|
||||||
|
:command:`python`:
|
||||||
|
|
||||||
|
.. code-block:: pycon
|
||||||
|
|
||||||
|
>>> import example
|
||||||
|
>>> example.add(1, 2)
|
||||||
|
3
|
||||||
|
>>> example.sub(1, 1)
|
||||||
|
0
|
||||||
|
|
||||||
|
As shown above, the various ``init_ex`` functions should be contained in
|
||||||
|
separate files that can be compiled independently from one another, and then
|
||||||
|
linked together into the same final shared object. Following this approach
|
||||||
|
will:
|
||||||
|
|
||||||
|
1. reduce memory requirements per compilation unit.
|
||||||
|
|
||||||
|
2. enable parallel builds (if desired).
|
||||||
|
|
||||||
|
3. allow for faster incremental builds. For instance, when a single class
|
||||||
|
definition is changed, only a subset of the binding code will generally need
|
||||||
|
to be recompiled.
|
||||||
|
|
||||||
|
"recursive template instantiation exceeded maximum depth of 256"
|
||||||
|
================================================================
|
||||||
|
|
||||||
|
If you receive an error about excessive recursive template evaluation, try
|
||||||
|
specifying a larger value, e.g. ``-ftemplate-depth=1024`` on GCC/Clang. The
|
||||||
|
culprit is generally the generation of function signatures at compile time
|
||||||
|
using C++14 template metaprogramming.
|
||||||
|
|
||||||
|
.. _`faq:hidden_visibility`:
|
||||||
|
|
||||||
|
"‘SomeClass’ declared with greater visibility than the type of its field ‘SomeClass::member’ [-Wattributes]"
|
||||||
|
============================================================================================================
|
||||||
|
|
||||||
|
This error typically indicates that you are compiling without the required
|
||||||
|
``-fvisibility`` flag. pybind11 code internally forces hidden visibility on
|
||||||
|
all internal code, but if non-hidden (and thus *exported*) code attempts to
|
||||||
|
include a pybind type (for example, ``py::object`` or ``py::list``) you can run
|
||||||
|
into this warning.
|
||||||
|
|
||||||
|
To avoid it, make sure you are specifying ``-fvisibility=hidden`` when
|
||||||
|
compiling pybind code.
|
||||||
|
|
||||||
|
As to why ``-fvisibility=hidden`` is necessary, because pybind modules could
|
||||||
|
have been compiled under different versions of pybind itself, it is also
|
||||||
|
important that the symbols defined in one module do not clash with the
|
||||||
|
potentially-incompatible symbols defined in another. While Python extension
|
||||||
|
modules are usually loaded with localized symbols (under POSIX systems
|
||||||
|
typically using ``dlopen`` with the ``RTLD_LOCAL`` flag), this Python default
|
||||||
|
can be changed, but even if it isn't it is not always enough to guarantee
|
||||||
|
complete independence of the symbols involved when not using
|
||||||
|
``-fvisibility=hidden``.
|
||||||
|
|
||||||
|
Additionally, ``-fvisiblity=hidden`` can deliver considerably binary size
|
||||||
|
savings. (See the following section for more details).
|
||||||
|
|
||||||
|
|
||||||
|
.. _`faq:symhidden`:
|
||||||
|
|
||||||
|
How can I create smaller binaries?
|
||||||
|
==================================
|
||||||
|
|
||||||
|
To do its job, pybind11 extensively relies on a programming technique known as
|
||||||
|
*template metaprogramming*, which is a way of performing computation at compile
|
||||||
|
time using type information. Template metaprogamming usually instantiates code
|
||||||
|
involving significant numbers of deeply nested types that are either completely
|
||||||
|
removed or reduced to just a few instructions during the compiler's optimization
|
||||||
|
phase. However, due to the nested nature of these types, the resulting symbol
|
||||||
|
names in the compiled extension library can be extremely long. For instance,
|
||||||
|
the included test suite contains the following symbol:
|
||||||
|
|
||||||
|
.. only:: html
|
||||||
|
|
||||||
|
.. code-block:: none
|
||||||
|
|
||||||
|
__ZN8pybind1112cpp_functionC1Iv8Example2JRNSt3__16vectorINS3_12basic_stringIwNS3_11char_traitsIwEENS3_9allocatorIwEEEENS8_ISA_EEEEEJNS_4nameENS_7siblingENS_9is_methodEA28_cEEEMT0_FT_DpT1_EDpRKT2_
|
||||||
|
|
||||||
|
.. only:: not html
|
||||||
|
|
||||||
|
.. code-block:: cpp
|
||||||
|
|
||||||
|
__ZN8pybind1112cpp_functionC1Iv8Example2JRNSt3__16vectorINS3_12basic_stringIwNS3_11char_traitsIwEENS3_9allocatorIwEEEENS8_ISA_EEEEEJNS_4nameENS_7siblingENS_9is_methodEA28_cEEEMT0_FT_DpT1_EDpRKT2_
|
||||||
|
|
||||||
|
which is the mangled form of the following function type:
|
||||||
|
|
||||||
|
.. code-block:: cpp
|
||||||
|
|
||||||
|
pybind11::cpp_function::cpp_function<void, Example2, std::__1::vector<std::__1::basic_string<wchar_t, std::__1::char_traits<wchar_t>, std::__1::allocator<wchar_t> >, std::__1::allocator<std::__1::basic_string<wchar_t, std::__1::char_traits<wchar_t>, std::__1::allocator<wchar_t> > > >&, pybind11::name, pybind11::sibling, pybind11::is_method, char [28]>(void (Example2::*)(std::__1::vector<std::__1::basic_string<wchar_t, std::__1::char_traits<wchar_t>, std::__1::allocator<wchar_t> >, std::__1::allocator<std::__1::basic_string<wchar_t, std::__1::char_traits<wchar_t>, std::__1::allocator<wchar_t> > > >&), pybind11::name const&, pybind11::sibling const&, pybind11::is_method const&, char const (&) [28])
|
||||||
|
|
||||||
|
The memory needed to store just the mangled name of this function (196 bytes)
|
||||||
|
is larger than the actual piece of code (111 bytes) it represents! On the other
|
||||||
|
hand, it's silly to even give this function a name -- after all, it's just a
|
||||||
|
tiny cog in a bigger piece of machinery that is not exposed to the outside
|
||||||
|
world. So we'll generally only want to export symbols for those functions which
|
||||||
|
are actually called from the outside.
|
||||||
|
|
||||||
|
This can be achieved by specifying the parameter ``-fvisibility=hidden`` to GCC
|
||||||
|
and Clang, which sets the default symbol visibility to *hidden*, which has a
|
||||||
|
tremendous impact on the final binary size of the resulting extension library.
|
||||||
|
(On Visual Studio, symbols are already hidden by default, so nothing needs to
|
||||||
|
be done there.)
|
||||||
|
|
||||||
|
In addition to decreasing binary size, ``-fvisibility=hidden`` also avoids
|
||||||
|
potential serious issues when loading multiple modules and is required for
|
||||||
|
proper pybind operation. See the previous FAQ entry for more details.
|
||||||
|
|
||||||
|
Working with ancient Visual Studio 2008 builds on Windows
|
||||||
|
=========================================================
|
||||||
|
|
||||||
|
The official Windows distributions of Python are compiled using truly
|
||||||
|
ancient versions of Visual Studio that lack good C++11 support. Some users
|
||||||
|
implicitly assume that it would be impossible to load a plugin built with
|
||||||
|
Visual Studio 2015 into a Python distribution that was compiled using Visual
|
||||||
|
Studio 2008. However, no such issue exists: it's perfectly legitimate to
|
||||||
|
interface DLLs that are built with different compilers and/or C libraries.
|
||||||
|
Common gotchas to watch out for involve not ``free()``-ing memory region
|
||||||
|
that that were ``malloc()``-ed in another shared library, using data
|
||||||
|
structures with incompatible ABIs, and so on. pybind11 is very careful not
|
||||||
|
to make these types of mistakes.
|
||||||
|
|
||||||
|
How can I properly handle Ctrl-C in long-running functions?
|
||||||
|
===========================================================
|
||||||
|
|
||||||
|
Ctrl-C is received by the Python interpreter, and holds it until the GIL
|
||||||
|
is released, so a long-running function won't be interrupted.
|
||||||
|
|
||||||
|
To interrupt from inside your function, you can use the ``PyErr_CheckSignals()``
|
||||||
|
function, that will tell if a signal has been raised on the Python side. This
|
||||||
|
function merely checks a flag, so its impact is negligible. When a signal has
|
||||||
|
been received, you must either explicitly interrupt execution by throwing
|
||||||
|
``py::error_already_set`` (which will propagate the existing
|
||||||
|
``KeyboardInterrupt``), or clear the error (which you usually will not want):
|
||||||
|
|
||||||
|
.. code-block:: cpp
|
||||||
|
|
||||||
|
PYBIND11_MODULE(example, m)
|
||||||
|
{
|
||||||
|
m.def("long running_func", []()
|
||||||
|
{
|
||||||
|
for (;;) {
|
||||||
|
if (PyErr_CheckSignals() != 0)
|
||||||
|
throw py::error_already_set();
|
||||||
|
// Long running iteration
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
Inconsistent detection of Python version in CMake and pybind11
|
||||||
|
==============================================================
|
||||||
|
|
||||||
|
The functions ``find_package(PythonInterp)`` and ``find_package(PythonLibs)`` provided by CMake
|
||||||
|
for Python version detection are not used by pybind11 due to unreliability and limitations that make
|
||||||
|
them unsuitable for pybind11's needs. Instead pybind provides its own, more reliable Python detection
|
||||||
|
CMake code. Conflicts can arise, however, when using pybind11 in a project that *also* uses the CMake
|
||||||
|
Python detection in a system with several Python versions installed.
|
||||||
|
|
||||||
|
This difference may cause inconsistencies and errors if *both* mechanisms are used in the same project. Consider the following
|
||||||
|
Cmake code executed in a system with Python 2.7 and 3.x installed:
|
||||||
|
|
||||||
|
.. code-block:: cmake
|
||||||
|
|
||||||
|
find_package(PythonInterp)
|
||||||
|
find_package(PythonLibs)
|
||||||
|
find_package(pybind11)
|
||||||
|
|
||||||
|
It will detect Python 2.7 and pybind11 will pick it as well.
|
||||||
|
|
||||||
|
In contrast this code:
|
||||||
|
|
||||||
|
.. code-block:: cmake
|
||||||
|
|
||||||
|
find_package(pybind11)
|
||||||
|
find_package(PythonInterp)
|
||||||
|
find_package(PythonLibs)
|
||||||
|
|
||||||
|
will detect Python 3.x for pybind11 and may crash on ``find_package(PythonLibs)`` afterwards.
|
||||||
|
|
||||||
|
It is advised to avoid using ``find_package(PythonInterp)`` and ``find_package(PythonLibs)`` from CMake and rely
|
||||||
|
on pybind11 in detecting Python version. If this is not possible CMake machinery should be called *before* including pybind11.
|
||||||
|
|
||||||
|
How to cite this project?
|
||||||
|
=========================
|
||||||
|
|
||||||
|
We suggest the following BibTeX template to cite pybind11 in scientific
|
||||||
|
discourse:
|
||||||
|
|
||||||
|
.. code-block:: bash
|
||||||
|
|
||||||
|
@misc{pybind11,
|
||||||
|
author = {Wenzel Jakob and Jason Rhinelander and Dean Moldovan},
|
||||||
|
year = {2017},
|
||||||
|
note = {https://github.com/pybind/pybind11},
|
||||||
|
title = {pybind11 -- Seamless operability between C++11 and Python}
|
||||||
|
}
|
47
3rdparty/pybind11/docs/index.rst
vendored
Normal file
47
3rdparty/pybind11/docs/index.rst
vendored
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
.. only: not latex
|
||||||
|
|
||||||
|
.. image:: pybind11-logo.png
|
||||||
|
|
||||||
|
pybind11 --- Seamless operability between C++11 and Python
|
||||||
|
==========================================================
|
||||||
|
|
||||||
|
.. only: not latex
|
||||||
|
|
||||||
|
Contents:
|
||||||
|
|
||||||
|
.. toctree::
|
||||||
|
:maxdepth: 1
|
||||||
|
|
||||||
|
intro
|
||||||
|
changelog
|
||||||
|
upgrade
|
||||||
|
|
||||||
|
.. toctree::
|
||||||
|
:caption: The Basics
|
||||||
|
:maxdepth: 2
|
||||||
|
|
||||||
|
basics
|
||||||
|
classes
|
||||||
|
compiling
|
||||||
|
|
||||||
|
.. toctree::
|
||||||
|
:caption: Advanced Topics
|
||||||
|
:maxdepth: 2
|
||||||
|
|
||||||
|
advanced/functions
|
||||||
|
advanced/classes
|
||||||
|
advanced/exceptions
|
||||||
|
advanced/smart_ptrs
|
||||||
|
advanced/cast/index
|
||||||
|
advanced/pycpp/index
|
||||||
|
advanced/embedding
|
||||||
|
advanced/misc
|
||||||
|
|
||||||
|
.. toctree::
|
||||||
|
:caption: Extra Information
|
||||||
|
:maxdepth: 1
|
||||||
|
|
||||||
|
faq
|
||||||
|
benchmark
|
||||||
|
limitations
|
||||||
|
reference
|
93
3rdparty/pybind11/docs/intro.rst
vendored
Normal file
93
3rdparty/pybind11/docs/intro.rst
vendored
Normal file
@ -0,0 +1,93 @@
|
|||||||
|
.. image:: pybind11-logo.png
|
||||||
|
|
||||||
|
About this project
|
||||||
|
==================
|
||||||
|
**pybind11** is a lightweight header-only library that exposes C++ types in Python
|
||||||
|
and vice versa, mainly to create Python bindings of existing C++ code. Its
|
||||||
|
goals and syntax are similar to the excellent `Boost.Python`_ library by David
|
||||||
|
Abrahams: to minimize boilerplate code in traditional extension modules by
|
||||||
|
inferring type information using compile-time introspection.
|
||||||
|
|
||||||
|
.. _Boost.Python: http://www.boost.org/doc/libs/release/libs/python/doc/index.html
|
||||||
|
|
||||||
|
The main issue with Boost.Python—and the reason for creating such a similar
|
||||||
|
project—is Boost. Boost is an enormously large and complex suite of utility
|
||||||
|
libraries that works with almost every C++ compiler in existence. This
|
||||||
|
compatibility has its cost: arcane template tricks and workarounds are
|
||||||
|
necessary to support the oldest and buggiest of compiler specimens. Now that
|
||||||
|
C++11-compatible compilers are widely available, this heavy machinery has
|
||||||
|
become an excessively large and unnecessary dependency.
|
||||||
|
Think of this library as a tiny self-contained version of Boost.Python with
|
||||||
|
everything stripped away that isn't relevant for binding generation. Without
|
||||||
|
comments, the core header files only require ~4K lines of code and depend on
|
||||||
|
Python (2.7 or 3.x, or PyPy2.7 >= 5.7) and the C++ standard library. This
|
||||||
|
compact implementation was possible thanks to some of the new C++11 language
|
||||||
|
features (specifically: tuples, lambda functions and variadic templates). Since
|
||||||
|
its creation, this library has grown beyond Boost.Python in many ways, leading
|
||||||
|
to dramatically simpler binding code in many common situations.
|
||||||
|
|
||||||
|
Core features
|
||||||
|
*************
|
||||||
|
The following core C++ features can be mapped to Python
|
||||||
|
|
||||||
|
- Functions accepting and returning custom data structures per value, reference, or pointer
|
||||||
|
- Instance methods and static methods
|
||||||
|
- Overloaded functions
|
||||||
|
- Instance attributes and static attributes
|
||||||
|
- Arbitrary exception types
|
||||||
|
- Enumerations
|
||||||
|
- Callbacks
|
||||||
|
- Iterators and ranges
|
||||||
|
- Custom operators
|
||||||
|
- Single and multiple inheritance
|
||||||
|
- STL data structures
|
||||||
|
- Smart pointers with reference counting like ``std::shared_ptr``
|
||||||
|
- Internal references with correct reference counting
|
||||||
|
- C++ classes with virtual (and pure virtual) methods can be extended in Python
|
||||||
|
|
||||||
|
Goodies
|
||||||
|
*******
|
||||||
|
In addition to the core functionality, pybind11 provides some extra goodies:
|
||||||
|
|
||||||
|
- Python 2.7, 3.x, and PyPy (PyPy2.7 >= 5.7) are supported with an
|
||||||
|
implementation-agnostic interface.
|
||||||
|
|
||||||
|
- It is possible to bind C++11 lambda functions with captured variables. The
|
||||||
|
lambda capture data is stored inside the resulting Python function object.
|
||||||
|
|
||||||
|
- pybind11 uses C++11 move constructors and move assignment operators whenever
|
||||||
|
possible to efficiently transfer custom data types.
|
||||||
|
|
||||||
|
- It's easy to expose the internal storage of custom data types through
|
||||||
|
Pythons' buffer protocols. This is handy e.g. for fast conversion between
|
||||||
|
C++ matrix classes like Eigen and NumPy without expensive copy operations.
|
||||||
|
|
||||||
|
- pybind11 can automatically vectorize functions so that they are transparently
|
||||||
|
applied to all entries of one or more NumPy array arguments.
|
||||||
|
|
||||||
|
- Python's slice-based access and assignment operations can be supported with
|
||||||
|
just a few lines of code.
|
||||||
|
|
||||||
|
- Everything is contained in just a few header files; there is no need to link
|
||||||
|
against any additional libraries.
|
||||||
|
|
||||||
|
- Binaries are generally smaller by a factor of at least 2 compared to
|
||||||
|
equivalent bindings generated by Boost.Python. A recent pybind11 conversion
|
||||||
|
of `PyRosetta`_, an enormous Boost.Python binding project, reported a binary
|
||||||
|
size reduction of **5.4x** and compile time reduction by **5.8x**.
|
||||||
|
|
||||||
|
- Function signatures are precomputed at compile time (using ``constexpr``),
|
||||||
|
leading to smaller binaries.
|
||||||
|
|
||||||
|
- With little extra effort, C++ types can be pickled and unpickled similar to
|
||||||
|
regular Python objects.
|
||||||
|
|
||||||
|
.. _PyRosetta: http://graylab.jhu.edu/RosettaCon2016/PyRosetta-4.pdf
|
||||||
|
|
||||||
|
Supported compilers
|
||||||
|
*******************
|
||||||
|
|
||||||
|
1. Clang/LLVM (any non-ancient version with C++11 support)
|
||||||
|
2. GCC 4.8 or newer
|
||||||
|
3. Microsoft Visual Studio 2015 or newer
|
||||||
|
4. Intel C++ compiler v17 or newer (v16 with pybind11 v2.0 and v15 with pybind11 v2.0 and a `workaround <https://github.com/pybind/pybind11/issues/276>`_ )
|
20
3rdparty/pybind11/docs/limitations.rst
vendored
Normal file
20
3rdparty/pybind11/docs/limitations.rst
vendored
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
Limitations
|
||||||
|
###########
|
||||||
|
|
||||||
|
pybind11 strives to be a general solution to binding generation, but it also has
|
||||||
|
certain limitations:
|
||||||
|
|
||||||
|
- pybind11 casts away ``const``-ness in function arguments and return values.
|
||||||
|
This is in line with the Python language, which has no concept of ``const``
|
||||||
|
values. This means that some additional care is needed to avoid bugs that
|
||||||
|
would be caught by the type checker in a traditional C++ program.
|
||||||
|
|
||||||
|
- The NumPy interface ``pybind11::array`` greatly simplifies accessing
|
||||||
|
numerical data from C++ (and vice versa), but it's not a full-blown array
|
||||||
|
class like ``Eigen::Array`` or ``boost.multi_array``.
|
||||||
|
|
||||||
|
These features could be implemented but would lead to a significant increase in
|
||||||
|
complexity. I've decided to draw the line here to keep this project simple and
|
||||||
|
compact. Users who absolutely require these features are encouraged to fork
|
||||||
|
pybind11.
|
||||||
|
|
BIN
3rdparty/pybind11/docs/pybind11-logo.png
vendored
Normal file
BIN
3rdparty/pybind11/docs/pybind11-logo.png
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 57 KiB |
BIN
3rdparty/pybind11/docs/pybind11_vs_boost_python1.png
vendored
Normal file
BIN
3rdparty/pybind11/docs/pybind11_vs_boost_python1.png
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 44 KiB |
BIN
3rdparty/pybind11/docs/pybind11_vs_boost_python1.svg
vendored
Normal file
BIN
3rdparty/pybind11/docs/pybind11_vs_boost_python1.svg
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 86 KiB |
BIN
3rdparty/pybind11/docs/pybind11_vs_boost_python2.png
vendored
Normal file
BIN
3rdparty/pybind11/docs/pybind11_vs_boost_python2.png
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 40 KiB |
BIN
3rdparty/pybind11/docs/pybind11_vs_boost_python2.svg
vendored
Normal file
BIN
3rdparty/pybind11/docs/pybind11_vs_boost_python2.svg
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 84 KiB |
117
3rdparty/pybind11/docs/reference.rst
vendored
Normal file
117
3rdparty/pybind11/docs/reference.rst
vendored
Normal file
@ -0,0 +1,117 @@
|
|||||||
|
.. _reference:
|
||||||
|
|
||||||
|
.. warning::
|
||||||
|
|
||||||
|
Please be advised that the reference documentation discussing pybind11
|
||||||
|
internals is currently incomplete. Please refer to the previous sections
|
||||||
|
and the pybind11 header files for the nitty gritty details.
|
||||||
|
|
||||||
|
Reference
|
||||||
|
#########
|
||||||
|
|
||||||
|
.. _macros:
|
||||||
|
|
||||||
|
Macros
|
||||||
|
======
|
||||||
|
|
||||||
|
.. doxygendefine:: PYBIND11_MODULE
|
||||||
|
|
||||||
|
.. _core_types:
|
||||||
|
|
||||||
|
Convenience classes for arbitrary Python types
|
||||||
|
==============================================
|
||||||
|
|
||||||
|
Common member functions
|
||||||
|
-----------------------
|
||||||
|
|
||||||
|
.. doxygenclass:: object_api
|
||||||
|
:members:
|
||||||
|
|
||||||
|
Without reference counting
|
||||||
|
--------------------------
|
||||||
|
|
||||||
|
.. doxygenclass:: handle
|
||||||
|
:members:
|
||||||
|
|
||||||
|
With reference counting
|
||||||
|
-----------------------
|
||||||
|
|
||||||
|
.. doxygenclass:: object
|
||||||
|
:members:
|
||||||
|
|
||||||
|
.. doxygenfunction:: reinterpret_borrow
|
||||||
|
|
||||||
|
.. doxygenfunction:: reinterpret_steal
|
||||||
|
|
||||||
|
Convenience classes for specific Python types
|
||||||
|
=============================================
|
||||||
|
|
||||||
|
.. doxygenclass:: module
|
||||||
|
:members:
|
||||||
|
|
||||||
|
.. doxygengroup:: pytypes
|
||||||
|
:members:
|
||||||
|
|
||||||
|
.. _extras:
|
||||||
|
|
||||||
|
Passing extra arguments to ``def`` or ``class_``
|
||||||
|
================================================
|
||||||
|
|
||||||
|
.. doxygengroup:: annotations
|
||||||
|
:members:
|
||||||
|
|
||||||
|
Embedding the interpreter
|
||||||
|
=========================
|
||||||
|
|
||||||
|
.. doxygendefine:: PYBIND11_EMBEDDED_MODULE
|
||||||
|
|
||||||
|
.. doxygenfunction:: initialize_interpreter
|
||||||
|
|
||||||
|
.. doxygenfunction:: finalize_interpreter
|
||||||
|
|
||||||
|
.. doxygenclass:: scoped_interpreter
|
||||||
|
|
||||||
|
Redirecting C++ streams
|
||||||
|
=======================
|
||||||
|
|
||||||
|
.. doxygenclass:: scoped_ostream_redirect
|
||||||
|
|
||||||
|
.. doxygenclass:: scoped_estream_redirect
|
||||||
|
|
||||||
|
.. doxygenfunction:: add_ostream_redirect
|
||||||
|
|
||||||
|
Python built-in functions
|
||||||
|
=========================
|
||||||
|
|
||||||
|
.. doxygengroup:: python_builtins
|
||||||
|
:members:
|
||||||
|
|
||||||
|
Inheritance
|
||||||
|
===========
|
||||||
|
|
||||||
|
See :doc:`/classes` and :doc:`/advanced/classes` for more detail.
|
||||||
|
|
||||||
|
.. doxygendefine:: PYBIND11_OVERLOAD
|
||||||
|
|
||||||
|
.. doxygendefine:: PYBIND11_OVERLOAD_PURE
|
||||||
|
|
||||||
|
.. doxygendefine:: PYBIND11_OVERLOAD_NAME
|
||||||
|
|
||||||
|
.. doxygendefine:: PYBIND11_OVERLOAD_PURE_NAME
|
||||||
|
|
||||||
|
.. doxygenfunction:: get_overload
|
||||||
|
|
||||||
|
Exceptions
|
||||||
|
==========
|
||||||
|
|
||||||
|
.. doxygenclass:: error_already_set
|
||||||
|
:members:
|
||||||
|
|
||||||
|
.. doxygenclass:: builtin_exception
|
||||||
|
:members:
|
||||||
|
|
||||||
|
|
||||||
|
Literals
|
||||||
|
========
|
||||||
|
|
||||||
|
.. doxygennamespace:: literals
|
21
3rdparty/pybind11/docs/release.rst
vendored
Normal file
21
3rdparty/pybind11/docs/release.rst
vendored
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
To release a new version of pybind11:
|
||||||
|
|
||||||
|
- Update the version number and push to pypi
|
||||||
|
- Update ``pybind11/_version.py`` (set release version, remove 'dev').
|
||||||
|
- Update ``PYBIND11_VERSION_MAJOR`` etc. in ``include/pybind11/detail/common.h``.
|
||||||
|
- Ensure that all the information in ``setup.py`` is up-to-date.
|
||||||
|
- Update version in ``docs/conf.py``.
|
||||||
|
- Tag release date in ``docs/changelog.rst``.
|
||||||
|
- ``git add`` and ``git commit``.
|
||||||
|
- if new minor version: ``git checkout -b vX.Y``, ``git push -u origin vX.Y``
|
||||||
|
- ``git tag -a vX.Y.Z -m 'vX.Y.Z release'``.
|
||||||
|
- ``git push``
|
||||||
|
- ``git push --tags``.
|
||||||
|
- ``python setup.py sdist upload``.
|
||||||
|
- ``python setup.py bdist_wheel upload``.
|
||||||
|
- Get back to work
|
||||||
|
- Update ``_version.py`` (add 'dev' and increment minor).
|
||||||
|
- Update version in ``docs/conf.py``
|
||||||
|
- Update version macros in ``include/pybind11/common.h``
|
||||||
|
- ``git add`` and ``git commit``.
|
||||||
|
``git push``
|
1
3rdparty/pybind11/docs/requirements.txt
vendored
Normal file
1
3rdparty/pybind11/docs/requirements.txt
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
breathe == 4.5.0
|
404
3rdparty/pybind11/docs/upgrade.rst
vendored
Normal file
404
3rdparty/pybind11/docs/upgrade.rst
vendored
Normal file
@ -0,0 +1,404 @@
|
|||||||
|
Upgrade guide
|
||||||
|
#############
|
||||||
|
|
||||||
|
This is a companion guide to the :doc:`changelog`. While the changelog briefly
|
||||||
|
lists all of the new features, improvements and bug fixes, this upgrade guide
|
||||||
|
focuses only the subset which directly impacts your experience when upgrading
|
||||||
|
to a new version. But it goes into more detail. This includes things like
|
||||||
|
deprecated APIs and their replacements, build system changes, general code
|
||||||
|
modernization and other useful information.
|
||||||
|
|
||||||
|
|
||||||
|
v2.2
|
||||||
|
====
|
||||||
|
|
||||||
|
Deprecation of the ``PYBIND11_PLUGIN`` macro
|
||||||
|
--------------------------------------------
|
||||||
|
|
||||||
|
``PYBIND11_MODULE`` is now the preferred way to create module entry points.
|
||||||
|
The old macro emits a compile-time deprecation warning.
|
||||||
|
|
||||||
|
.. code-block:: cpp
|
||||||
|
|
||||||
|
// old
|
||||||
|
PYBIND11_PLUGIN(example) {
|
||||||
|
py::module m("example", "documentation string");
|
||||||
|
|
||||||
|
m.def("add", [](int a, int b) { return a + b; });
|
||||||
|
|
||||||
|
return m.ptr();
|
||||||
|
}
|
||||||
|
|
||||||
|
// new
|
||||||
|
PYBIND11_MODULE(example, m) {
|
||||||
|
m.doc() = "documentation string"; // optional
|
||||||
|
|
||||||
|
m.def("add", [](int a, int b) { return a + b; });
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
New API for defining custom constructors and pickling functions
|
||||||
|
---------------------------------------------------------------
|
||||||
|
|
||||||
|
The old placement-new custom constructors have been deprecated. The new approach
|
||||||
|
uses ``py::init()`` and factory functions to greatly improve type safety.
|
||||||
|
|
||||||
|
Placement-new can be called accidentally with an incompatible type (without any
|
||||||
|
compiler errors or warnings), or it can initialize the same object multiple times
|
||||||
|
if not careful with the Python-side ``__init__`` calls. The new-style custom
|
||||||
|
constructors prevent such mistakes. See :ref:`custom_constructors` for details.
|
||||||
|
|
||||||
|
.. code-block:: cpp
|
||||||
|
|
||||||
|
// old -- deprecated (runtime warning shown only in debug mode)
|
||||||
|
py::class<Foo>(m, "Foo")
|
||||||
|
.def("__init__", [](Foo &self, ...) {
|
||||||
|
new (&self) Foo(...); // uses placement-new
|
||||||
|
});
|
||||||
|
|
||||||
|
// new
|
||||||
|
py::class<Foo>(m, "Foo")
|
||||||
|
.def(py::init([](...) { // Note: no `self` argument
|
||||||
|
return new Foo(...); // return by raw pointer
|
||||||
|
// or: return std::make_unique<Foo>(...); // return by holder
|
||||||
|
// or: return Foo(...); // return by value (move constructor)
|
||||||
|
}));
|
||||||
|
|
||||||
|
Mirroring the custom constructor changes, ``py::pickle()`` is now the preferred
|
||||||
|
way to get and set object state. See :ref:`pickling` for details.
|
||||||
|
|
||||||
|
.. code-block:: cpp
|
||||||
|
|
||||||
|
// old -- deprecated (runtime warning shown only in debug mode)
|
||||||
|
py::class<Foo>(m, "Foo")
|
||||||
|
...
|
||||||
|
.def("__getstate__", [](const Foo &self) {
|
||||||
|
return py::make_tuple(self.value1(), self.value2(), ...);
|
||||||
|
})
|
||||||
|
.def("__setstate__", [](Foo &self, py::tuple t) {
|
||||||
|
new (&self) Foo(t[0].cast<std::string>(), ...);
|
||||||
|
});
|
||||||
|
|
||||||
|
// new
|
||||||
|
py::class<Foo>(m, "Foo")
|
||||||
|
...
|
||||||
|
.def(py::pickle(
|
||||||
|
[](const Foo &self) { // __getstate__
|
||||||
|
return py::make_tuple(f.value1(), f.value2(), ...); // unchanged
|
||||||
|
},
|
||||||
|
[](py::tuple t) { // __setstate__, note: no `self` argument
|
||||||
|
return new Foo(t[0].cast<std::string>(), ...);
|
||||||
|
// or: return std::make_unique<Foo>(...); // return by holder
|
||||||
|
// or: return Foo(...); // return by value (move constructor)
|
||||||
|
}
|
||||||
|
));
|
||||||
|
|
||||||
|
For both the constructors and pickling, warnings are shown at module
|
||||||
|
initialization time (on import, not when the functions are called).
|
||||||
|
They're only visible when compiled in debug mode. Sample warning:
|
||||||
|
|
||||||
|
.. code-block:: none
|
||||||
|
|
||||||
|
pybind11-bound class 'mymodule.Foo' is using an old-style placement-new '__init__'
|
||||||
|
which has been deprecated. See the upgrade guide in pybind11's docs.
|
||||||
|
|
||||||
|
|
||||||
|
Stricter enforcement of hidden symbol visibility for pybind11 modules
|
||||||
|
---------------------------------------------------------------------
|
||||||
|
|
||||||
|
pybind11 now tries to actively enforce hidden symbol visibility for modules.
|
||||||
|
If you're using either one of pybind11's :doc:`CMake or Python build systems
|
||||||
|
<compiling>` (the two example repositories) and you haven't been exporting any
|
||||||
|
symbols, there's nothing to be concerned about. All the changes have been done
|
||||||
|
transparently in the background. If you were building manually or relied on
|
||||||
|
specific default visibility, read on.
|
||||||
|
|
||||||
|
Setting default symbol visibility to *hidden* has always been recommended for
|
||||||
|
pybind11 (see :ref:`faq:symhidden`). On Linux and macOS, hidden symbol
|
||||||
|
visibility (in conjunction with the ``strip`` utility) yields much smaller
|
||||||
|
module binaries. `CPython's extension docs`_ also recommend hiding symbols
|
||||||
|
by default, with the goal of avoiding symbol name clashes between modules.
|
||||||
|
Starting with v2.2, pybind11 enforces this more strictly: (1) by declaring
|
||||||
|
all symbols inside the ``pybind11`` namespace as hidden and (2) by including
|
||||||
|
the ``-fvisibility=hidden`` flag on Linux and macOS (only for extension
|
||||||
|
modules, not for embedding the interpreter).
|
||||||
|
|
||||||
|
.. _CPython's extension docs: https://docs.python.org/3/extending/extending.html#providing-a-c-api-for-an-extension-module
|
||||||
|
|
||||||
|
The namespace-scope hidden visibility is done automatically in pybind11's
|
||||||
|
headers and it's generally transparent to users. It ensures that:
|
||||||
|
|
||||||
|
* Modules compiled with different pybind11 versions don't clash with each other.
|
||||||
|
|
||||||
|
* Some new features, like ``py::module_local`` bindings, can work as intended.
|
||||||
|
|
||||||
|
The ``-fvisibility=hidden`` flag applies the same visibility to user bindings
|
||||||
|
outside of the ``pybind11`` namespace. It's now set automatic by pybind11's
|
||||||
|
CMake and Python build systems, but this needs to be done manually by users
|
||||||
|
of other build systems. Adding this flag:
|
||||||
|
|
||||||
|
* Minimizes the chances of symbol conflicts between modules. E.g. if two
|
||||||
|
unrelated modules were statically linked to different (ABI-incompatible)
|
||||||
|
versions of the same third-party library, a symbol clash would be likely
|
||||||
|
(and would end with unpredictable results).
|
||||||
|
|
||||||
|
* Produces smaller binaries on Linux and macOS, as pointed out previously.
|
||||||
|
|
||||||
|
Within pybind11's CMake build system, ``pybind11_add_module`` has always been
|
||||||
|
setting the ``-fvisibility=hidden`` flag in release mode. From now on, it's
|
||||||
|
being applied unconditionally, even in debug mode and it can no longer be opted
|
||||||
|
out of with the ``NO_EXTRAS`` option. The ``pybind11::module`` target now also
|
||||||
|
adds this flag to it's interface. The ``pybind11::embed`` target is unchanged.
|
||||||
|
|
||||||
|
The most significant change here is for the ``pybind11::module`` target. If you
|
||||||
|
were previously relying on default visibility, i.e. if your Python module was
|
||||||
|
doubling as a shared library with dependents, you'll need to either export
|
||||||
|
symbols manually (recommended for cross-platform libraries) or factor out the
|
||||||
|
shared library (and have the Python module link to it like the other
|
||||||
|
dependents). As a temporary workaround, you can also restore default visibility
|
||||||
|
using the CMake code below, but this is not recommended in the long run:
|
||||||
|
|
||||||
|
.. code-block:: cmake
|
||||||
|
|
||||||
|
target_link_libraries(mymodule PRIVATE pybind11::module)
|
||||||
|
|
||||||
|
add_library(restore_default_visibility INTERFACE)
|
||||||
|
target_compile_options(restore_default_visibility INTERFACE -fvisibility=default)
|
||||||
|
target_link_libraries(mymodule PRIVATE restore_default_visibility)
|
||||||
|
|
||||||
|
|
||||||
|
Local STL container bindings
|
||||||
|
----------------------------
|
||||||
|
|
||||||
|
Previous pybind11 versions could only bind types globally -- all pybind11
|
||||||
|
modules, even unrelated ones, would have access to the same exported types.
|
||||||
|
However, this would also result in a conflict if two modules exported the
|
||||||
|
same C++ type, which is especially problematic for very common types, e.g.
|
||||||
|
``std::vector<int>``. :ref:`module_local` were added to resolve this (see
|
||||||
|
that section for a complete usage guide).
|
||||||
|
|
||||||
|
``py::class_`` still defaults to global bindings (because these types are
|
||||||
|
usually unique across modules), however in order to avoid clashes of opaque
|
||||||
|
types, ``py::bind_vector`` and ``py::bind_map`` will now bind STL containers
|
||||||
|
as ``py::module_local`` if their elements are: builtins (``int``, ``float``,
|
||||||
|
etc.), not bound using ``py::class_``, or bound as ``py::module_local``. For
|
||||||
|
example, this change allows multiple modules to bind ``std::vector<int>``
|
||||||
|
without causing conflicts. See :ref:`stl_bind` for more details.
|
||||||
|
|
||||||
|
When upgrading to this version, if you have multiple modules which depend on
|
||||||
|
a single global binding of an STL container, note that all modules can still
|
||||||
|
accept foreign ``py::module_local`` types in the direction of Python-to-C++.
|
||||||
|
The locality only affects the C++-to-Python direction. If this is needed in
|
||||||
|
multiple modules, you'll need to either:
|
||||||
|
|
||||||
|
* Add a copy of the same STL binding to all of the modules which need it.
|
||||||
|
|
||||||
|
* Restore the global status of that single binding by marking it
|
||||||
|
``py::module_local(false)``.
|
||||||
|
|
||||||
|
The latter is an easy workaround, but in the long run it would be best to
|
||||||
|
localize all common type bindings in order to avoid conflicts with
|
||||||
|
third-party modules.
|
||||||
|
|
||||||
|
|
||||||
|
Negative strides for Python buffer objects and numpy arrays
|
||||||
|
-----------------------------------------------------------
|
||||||
|
|
||||||
|
Support for negative strides required changing the integer type from unsigned
|
||||||
|
to signed in the interfaces of ``py::buffer_info`` and ``py::array``. If you
|
||||||
|
have compiler warnings enabled, you may notice some new conversion warnings
|
||||||
|
after upgrading. These can be resolved using ``static_cast``.
|
||||||
|
|
||||||
|
|
||||||
|
Deprecation of some ``py::object`` APIs
|
||||||
|
---------------------------------------
|
||||||
|
|
||||||
|
To compare ``py::object`` instances by pointer, you should now use
|
||||||
|
``obj1.is(obj2)`` which is equivalent to ``obj1 is obj2`` in Python.
|
||||||
|
Previously, pybind11 used ``operator==`` for this (``obj1 == obj2``), but
|
||||||
|
that could be confusing and is now deprecated (so that it can eventually
|
||||||
|
be replaced with proper rich object comparison in a future release).
|
||||||
|
|
||||||
|
For classes which inherit from ``py::object``, ``borrowed`` and ``stolen``
|
||||||
|
were previously available as protected constructor tags. Now the types
|
||||||
|
should be used directly instead: ``borrowed_t{}`` and ``stolen_t{}``
|
||||||
|
(`#771 <https://github.com/pybind/pybind11/pull/771>`_).
|
||||||
|
|
||||||
|
|
||||||
|
Stricter compile-time error checking
|
||||||
|
------------------------------------
|
||||||
|
|
||||||
|
Some error checks have been moved from run time to compile time. Notably,
|
||||||
|
automatic conversion of ``std::shared_ptr<T>`` is not possible when ``T`` is
|
||||||
|
not directly registered with ``py::class_<T>`` (e.g. ``std::shared_ptr<int>``
|
||||||
|
or ``std::shared_ptr<std::vector<T>>`` are not automatically convertible).
|
||||||
|
Attempting to bind a function with such arguments now results in a compile-time
|
||||||
|
error instead of waiting to fail at run time.
|
||||||
|
|
||||||
|
``py::init<...>()`` constructor definitions are also stricter and now prevent
|
||||||
|
bindings which could cause unexpected behavior:
|
||||||
|
|
||||||
|
.. code-block:: cpp
|
||||||
|
|
||||||
|
struct Example {
|
||||||
|
Example(int &);
|
||||||
|
};
|
||||||
|
|
||||||
|
py::class_<Example>(m, "Example")
|
||||||
|
.def(py::init<int &>()); // OK, exact match
|
||||||
|
// .def(py::init<int>()); // compile-time error, mismatch
|
||||||
|
|
||||||
|
A non-``const`` lvalue reference is not allowed to bind to an rvalue. However,
|
||||||
|
note that a constructor taking ``const T &`` can still be registered using
|
||||||
|
``py::init<T>()`` because a ``const`` lvalue reference can bind to an rvalue.
|
||||||
|
|
||||||
|
v2.1
|
||||||
|
====
|
||||||
|
|
||||||
|
Minimum compiler versions are enforced at compile time
|
||||||
|
------------------------------------------------------
|
||||||
|
|
||||||
|
The minimums also apply to v2.0 but the check is now explicit and a compile-time
|
||||||
|
error is raised if the compiler does not meet the requirements:
|
||||||
|
|
||||||
|
* GCC >= 4.8
|
||||||
|
* clang >= 3.3 (appleclang >= 5.0)
|
||||||
|
* MSVC >= 2015u3
|
||||||
|
* Intel C++ >= 15.0
|
||||||
|
|
||||||
|
|
||||||
|
The ``py::metaclass`` attribute is not required for static properties
|
||||||
|
---------------------------------------------------------------------
|
||||||
|
|
||||||
|
Binding classes with static properties is now possible by default. The
|
||||||
|
zero-parameter version of ``py::metaclass()`` is deprecated. However, a new
|
||||||
|
one-parameter ``py::metaclass(python_type)`` version was added for rare
|
||||||
|
cases when a custom metaclass is needed to override pybind11's default.
|
||||||
|
|
||||||
|
.. code-block:: cpp
|
||||||
|
|
||||||
|
// old -- emits a deprecation warning
|
||||||
|
py::class_<Foo>(m, "Foo", py::metaclass())
|
||||||
|
.def_property_readonly_static("foo", ...);
|
||||||
|
|
||||||
|
// new -- static properties work without the attribute
|
||||||
|
py::class_<Foo>(m, "Foo")
|
||||||
|
.def_property_readonly_static("foo", ...);
|
||||||
|
|
||||||
|
// new -- advanced feature, override pybind11's default metaclass
|
||||||
|
py::class_<Bar>(m, "Bar", py::metaclass(custom_python_type))
|
||||||
|
...
|
||||||
|
|
||||||
|
|
||||||
|
v2.0
|
||||||
|
====
|
||||||
|
|
||||||
|
Breaking changes in ``py::class_``
|
||||||
|
----------------------------------
|
||||||
|
|
||||||
|
These changes were necessary to make type definitions in pybind11
|
||||||
|
future-proof, to support PyPy via its ``cpyext`` mechanism (`#527
|
||||||
|
<https://github.com/pybind/pybind11/pull/527>`_), and to improve efficiency
|
||||||
|
(`rev. 86d825 <https://github.com/pybind/pybind11/commit/86d825>`_).
|
||||||
|
|
||||||
|
1. Declarations of types that provide access via the buffer protocol must
|
||||||
|
now include the ``py::buffer_protocol()`` annotation as an argument to
|
||||||
|
the ``py::class_`` constructor.
|
||||||
|
|
||||||
|
.. code-block:: cpp
|
||||||
|
|
||||||
|
py::class_<Matrix>("Matrix", py::buffer_protocol())
|
||||||
|
.def(py::init<...>())
|
||||||
|
.def_buffer(...);
|
||||||
|
|
||||||
|
2. Classes which include static properties (e.g. ``def_readwrite_static()``)
|
||||||
|
must now include the ``py::metaclass()`` attribute. Note: this requirement
|
||||||
|
has since been removed in v2.1. If you're upgrading from 1.x, it's
|
||||||
|
recommended to skip directly to v2.1 or newer.
|
||||||
|
|
||||||
|
3. This version of pybind11 uses a redesigned mechanism for instantiating
|
||||||
|
trampoline classes that are used to override virtual methods from within
|
||||||
|
Python. This led to the following user-visible syntax change:
|
||||||
|
|
||||||
|
.. code-block:: cpp
|
||||||
|
|
||||||
|
// old v1.x syntax
|
||||||
|
py::class_<TrampolineClass>("MyClass")
|
||||||
|
.alias<MyClass>()
|
||||||
|
...
|
||||||
|
|
||||||
|
// new v2.x syntax
|
||||||
|
py::class_<MyClass, TrampolineClass>("MyClass")
|
||||||
|
...
|
||||||
|
|
||||||
|
Importantly, both the original and the trampoline class are now specified
|
||||||
|
as arguments to the ``py::class_`` template, and the ``alias<..>()`` call
|
||||||
|
is gone. The new scheme has zero overhead in cases when Python doesn't
|
||||||
|
override any functions of the underlying C++ class.
|
||||||
|
`rev. 86d825 <https://github.com/pybind/pybind11/commit/86d825>`_.
|
||||||
|
|
||||||
|
The class type must be the first template argument given to ``py::class_``
|
||||||
|
while the trampoline can be mixed in arbitrary order with other arguments
|
||||||
|
(see the following section).
|
||||||
|
|
||||||
|
|
||||||
|
Deprecation of the ``py::base<T>()`` attribute
|
||||||
|
----------------------------------------------
|
||||||
|
|
||||||
|
``py::base<T>()`` was deprecated in favor of specifying ``T`` as a template
|
||||||
|
argument to ``py::class_``. This new syntax also supports multiple inheritance.
|
||||||
|
Note that, while the type being exported must be the first argument in the
|
||||||
|
``py::class_<Class, ...>`` template, the order of the following types (bases,
|
||||||
|
holder and/or trampoline) is not important.
|
||||||
|
|
||||||
|
.. code-block:: cpp
|
||||||
|
|
||||||
|
// old v1.x
|
||||||
|
py::class_<Derived>("Derived", py::base<Base>());
|
||||||
|
|
||||||
|
// new v2.x
|
||||||
|
py::class_<Derived, Base>("Derived");
|
||||||
|
|
||||||
|
// new -- multiple inheritance
|
||||||
|
py::class_<Derived, Base1, Base2>("Derived");
|
||||||
|
|
||||||
|
// new -- apart from `Derived` the argument order can be arbitrary
|
||||||
|
py::class_<Derived, Base1, Holder, Base2, Trampoline>("Derived");
|
||||||
|
|
||||||
|
|
||||||
|
Out-of-the-box support for ``std::shared_ptr``
|
||||||
|
----------------------------------------------
|
||||||
|
|
||||||
|
The relevant type caster is now built in, so it's no longer necessary to
|
||||||
|
include a declaration of the form:
|
||||||
|
|
||||||
|
.. code-block:: cpp
|
||||||
|
|
||||||
|
PYBIND11_DECLARE_HOLDER_TYPE(T, std::shared_ptr<T>)
|
||||||
|
|
||||||
|
Continuing to do so won’t cause an error or even a deprecation warning,
|
||||||
|
but it's completely redundant.
|
||||||
|
|
||||||
|
|
||||||
|
Deprecation of a few ``py::object`` APIs
|
||||||
|
----------------------------------------
|
||||||
|
|
||||||
|
All of the old-style calls emit deprecation warnings.
|
||||||
|
|
||||||
|
+---------------------------------------+---------------------------------------------+
|
||||||
|
| Old syntax | New syntax |
|
||||||
|
+=======================================+=============================================+
|
||||||
|
| ``obj.call(args...)`` | ``obj(args...)`` |
|
||||||
|
+---------------------------------------+---------------------------------------------+
|
||||||
|
| ``obj.str()`` | ``py::str(obj)`` |
|
||||||
|
+---------------------------------------+---------------------------------------------+
|
||||||
|
| ``auto l = py::list(obj); l.check()`` | ``py::isinstance<py::list>(obj)`` |
|
||||||
|
+---------------------------------------+---------------------------------------------+
|
||||||
|
| ``py::object(ptr, true)`` | ``py::reinterpret_borrow<py::object>(ptr)`` |
|
||||||
|
+---------------------------------------+---------------------------------------------+
|
||||||
|
| ``py::object(ptr, false)`` | ``py::reinterpret_steal<py::object>(ptr)`` |
|
||||||
|
+---------------------------------------+---------------------------------------------+
|
||||||
|
| ``if (obj.attr("foo"))`` | ``if (py::hasattr(obj, "foo"))`` |
|
||||||
|
+---------------------------------------+---------------------------------------------+
|
||||||
|
| ``if (obj["bar"])`` | ``if (obj.contains("bar"))`` |
|
||||||
|
+---------------------------------------+---------------------------------------------+
|
493
3rdparty/pybind11/include/pybind11/attr.h
vendored
Normal file
493
3rdparty/pybind11/include/pybind11/attr.h
vendored
Normal file
@ -0,0 +1,493 @@
|
|||||||
|
/*
|
||||||
|
pybind11/attr.h: Infrastructure for processing custom
|
||||||
|
type and function attributes
|
||||||
|
|
||||||
|
Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch>
|
||||||
|
|
||||||
|
All rights reserved. Use of this source code is governed by a
|
||||||
|
BSD-style license that can be found in the LICENSE file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "cast.h"
|
||||||
|
|
||||||
|
NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
|
||||||
|
|
||||||
|
/// \addtogroup annotations
|
||||||
|
/// @{
|
||||||
|
|
||||||
|
/// Annotation for methods
|
||||||
|
struct is_method { handle class_; is_method(const handle &c) : class_(c) { } };
|
||||||
|
|
||||||
|
/// Annotation for operators
|
||||||
|
struct is_operator { };
|
||||||
|
|
||||||
|
/// Annotation for parent scope
|
||||||
|
struct scope { handle value; scope(const handle &s) : value(s) { } };
|
||||||
|
|
||||||
|
/// Annotation for documentation
|
||||||
|
struct doc { const char *value; doc(const char *value) : value(value) { } };
|
||||||
|
|
||||||
|
/// Annotation for function names
|
||||||
|
struct name { const char *value; name(const char *value) : value(value) { } };
|
||||||
|
|
||||||
|
/// Annotation indicating that a function is an overload associated with a given "sibling"
|
||||||
|
struct sibling { handle value; sibling(const handle &value) : value(value.ptr()) { } };
|
||||||
|
|
||||||
|
/// Annotation indicating that a class derives from another given type
|
||||||
|
template <typename T> struct base {
|
||||||
|
PYBIND11_DEPRECATED("base<T>() was deprecated in favor of specifying 'T' as a template argument to class_")
|
||||||
|
base() { }
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Keep patient alive while nurse lives
|
||||||
|
template <size_t Nurse, size_t Patient> struct keep_alive { };
|
||||||
|
|
||||||
|
/// Annotation indicating that a class is involved in a multiple inheritance relationship
|
||||||
|
struct multiple_inheritance { };
|
||||||
|
|
||||||
|
/// Annotation which enables dynamic attributes, i.e. adds `__dict__` to a class
|
||||||
|
struct dynamic_attr { };
|
||||||
|
|
||||||
|
/// Annotation which enables the buffer protocol for a type
|
||||||
|
struct buffer_protocol { };
|
||||||
|
|
||||||
|
/// Annotation which requests that a special metaclass is created for a type
|
||||||
|
struct metaclass {
|
||||||
|
handle value;
|
||||||
|
|
||||||
|
PYBIND11_DEPRECATED("py::metaclass() is no longer required. It's turned on by default now.")
|
||||||
|
metaclass() {}
|
||||||
|
|
||||||
|
/// Override pybind11's default metaclass
|
||||||
|
explicit metaclass(handle value) : value(value) { }
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Annotation that marks a class as local to the module:
|
||||||
|
struct module_local { const bool value; constexpr module_local(bool v = true) : value(v) { } };
|
||||||
|
|
||||||
|
/// Annotation to mark enums as an arithmetic type
|
||||||
|
struct arithmetic { };
|
||||||
|
|
||||||
|
/** \rst
|
||||||
|
A call policy which places one or more guard variables (``Ts...``) around the function call.
|
||||||
|
|
||||||
|
For example, this definition:
|
||||||
|
|
||||||
|
.. code-block:: cpp
|
||||||
|
|
||||||
|
m.def("foo", foo, py::call_guard<T>());
|
||||||
|
|
||||||
|
is equivalent to the following pseudocode:
|
||||||
|
|
||||||
|
.. code-block:: cpp
|
||||||
|
|
||||||
|
m.def("foo", [](args...) {
|
||||||
|
T scope_guard;
|
||||||
|
return foo(args...); // forwarded arguments
|
||||||
|
});
|
||||||
|
\endrst */
|
||||||
|
template <typename... Ts> struct call_guard;
|
||||||
|
|
||||||
|
template <> struct call_guard<> { using type = detail::void_type; };
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
struct call_guard<T> {
|
||||||
|
static_assert(std::is_default_constructible<T>::value,
|
||||||
|
"The guard type must be default constructible");
|
||||||
|
|
||||||
|
using type = T;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T, typename... Ts>
|
||||||
|
struct call_guard<T, Ts...> {
|
||||||
|
struct type {
|
||||||
|
T guard{}; // Compose multiple guard types with left-to-right default-constructor order
|
||||||
|
typename call_guard<Ts...>::type next{};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
/// @} annotations
|
||||||
|
|
||||||
|
NAMESPACE_BEGIN(detail)
|
||||||
|
/* Forward declarations */
|
||||||
|
enum op_id : int;
|
||||||
|
enum op_type : int;
|
||||||
|
struct undefined_t;
|
||||||
|
template <op_id id, op_type ot, typename L = undefined_t, typename R = undefined_t> struct op_;
|
||||||
|
inline void keep_alive_impl(size_t Nurse, size_t Patient, function_call &call, handle ret);
|
||||||
|
|
||||||
|
/// Internal data structure which holds metadata about a keyword argument
|
||||||
|
struct argument_record {
|
||||||
|
const char *name; ///< Argument name
|
||||||
|
const char *descr; ///< Human-readable version of the argument value
|
||||||
|
handle value; ///< Associated Python object
|
||||||
|
bool convert : 1; ///< True if the argument is allowed to convert when loading
|
||||||
|
bool none : 1; ///< True if None is allowed when loading
|
||||||
|
|
||||||
|
argument_record(const char *name, const char *descr, handle value, bool convert, bool none)
|
||||||
|
: name(name), descr(descr), value(value), convert(convert), none(none) { }
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Internal data structure which holds metadata about a bound function (signature, overloads, etc.)
|
||||||
|
struct function_record {
|
||||||
|
function_record()
|
||||||
|
: is_constructor(false), is_new_style_constructor(false), is_stateless(false),
|
||||||
|
is_operator(false), has_args(false), has_kwargs(false), is_method(false) { }
|
||||||
|
|
||||||
|
/// Function name
|
||||||
|
char *name = nullptr; /* why no C++ strings? They generate heavier code.. */
|
||||||
|
|
||||||
|
// User-specified documentation string
|
||||||
|
char *doc = nullptr;
|
||||||
|
|
||||||
|
/// Human-readable version of the function signature
|
||||||
|
char *signature = nullptr;
|
||||||
|
|
||||||
|
/// List of registered keyword arguments
|
||||||
|
std::vector<argument_record> args;
|
||||||
|
|
||||||
|
/// Pointer to lambda function which converts arguments and performs the actual call
|
||||||
|
handle (*impl) (function_call &) = nullptr;
|
||||||
|
|
||||||
|
/// Storage for the wrapped function pointer and captured data, if any
|
||||||
|
void *data[3] = { };
|
||||||
|
|
||||||
|
/// Pointer to custom destructor for 'data' (if needed)
|
||||||
|
void (*free_data) (function_record *ptr) = nullptr;
|
||||||
|
|
||||||
|
/// Return value policy associated with this function
|
||||||
|
return_value_policy policy = return_value_policy::automatic;
|
||||||
|
|
||||||
|
/// True if name == '__init__'
|
||||||
|
bool is_constructor : 1;
|
||||||
|
|
||||||
|
/// True if this is a new-style `__init__` defined in `detail/init.h`
|
||||||
|
bool is_new_style_constructor : 1;
|
||||||
|
|
||||||
|
/// True if this is a stateless function pointer
|
||||||
|
bool is_stateless : 1;
|
||||||
|
|
||||||
|
/// True if this is an operator (__add__), etc.
|
||||||
|
bool is_operator : 1;
|
||||||
|
|
||||||
|
/// True if the function has a '*args' argument
|
||||||
|
bool has_args : 1;
|
||||||
|
|
||||||
|
/// True if the function has a '**kwargs' argument
|
||||||
|
bool has_kwargs : 1;
|
||||||
|
|
||||||
|
/// True if this is a method
|
||||||
|
bool is_method : 1;
|
||||||
|
|
||||||
|
/// Number of arguments (including py::args and/or py::kwargs, if present)
|
||||||
|
std::uint16_t nargs;
|
||||||
|
|
||||||
|
/// Python method object
|
||||||
|
PyMethodDef *def = nullptr;
|
||||||
|
|
||||||
|
/// Python handle to the parent scope (a class or a module)
|
||||||
|
handle scope;
|
||||||
|
|
||||||
|
/// Python handle to the sibling function representing an overload chain
|
||||||
|
handle sibling;
|
||||||
|
|
||||||
|
/// Pointer to next overload
|
||||||
|
function_record *next = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Special data structure which (temporarily) holds metadata about a bound class
|
||||||
|
struct type_record {
|
||||||
|
PYBIND11_NOINLINE type_record()
|
||||||
|
: multiple_inheritance(false), dynamic_attr(false), buffer_protocol(false),
|
||||||
|
default_holder(true), module_local(false) { }
|
||||||
|
|
||||||
|
/// Handle to the parent scope
|
||||||
|
handle scope;
|
||||||
|
|
||||||
|
/// Name of the class
|
||||||
|
const char *name = nullptr;
|
||||||
|
|
||||||
|
// Pointer to RTTI type_info data structure
|
||||||
|
const std::type_info *type = nullptr;
|
||||||
|
|
||||||
|
/// How large is the underlying C++ type?
|
||||||
|
size_t type_size = 0;
|
||||||
|
|
||||||
|
/// What is the alignment of the underlying C++ type?
|
||||||
|
size_t type_align = 0;
|
||||||
|
|
||||||
|
/// How large is the type's holder?
|
||||||
|
size_t holder_size = 0;
|
||||||
|
|
||||||
|
/// The global operator new can be overridden with a class-specific variant
|
||||||
|
void *(*operator_new)(size_t) = nullptr;
|
||||||
|
|
||||||
|
/// Function pointer to class_<..>::init_instance
|
||||||
|
void (*init_instance)(instance *, const void *) = nullptr;
|
||||||
|
|
||||||
|
/// Function pointer to class_<..>::dealloc
|
||||||
|
void (*dealloc)(detail::value_and_holder &) = nullptr;
|
||||||
|
|
||||||
|
/// List of base classes of the newly created type
|
||||||
|
list bases;
|
||||||
|
|
||||||
|
/// Optional docstring
|
||||||
|
const char *doc = nullptr;
|
||||||
|
|
||||||
|
/// Custom metaclass (optional)
|
||||||
|
handle metaclass;
|
||||||
|
|
||||||
|
/// Multiple inheritance marker
|
||||||
|
bool multiple_inheritance : 1;
|
||||||
|
|
||||||
|
/// Does the class manage a __dict__?
|
||||||
|
bool dynamic_attr : 1;
|
||||||
|
|
||||||
|
/// Does the class implement the buffer protocol?
|
||||||
|
bool buffer_protocol : 1;
|
||||||
|
|
||||||
|
/// Is the default (unique_ptr) holder type used?
|
||||||
|
bool default_holder : 1;
|
||||||
|
|
||||||
|
/// Is the class definition local to the module shared object?
|
||||||
|
bool module_local : 1;
|
||||||
|
|
||||||
|
PYBIND11_NOINLINE void add_base(const std::type_info &base, void *(*caster)(void *)) {
|
||||||
|
auto base_info = detail::get_type_info(base, false);
|
||||||
|
if (!base_info) {
|
||||||
|
std::string tname(base.name());
|
||||||
|
detail::clean_type_id(tname);
|
||||||
|
pybind11_fail("generic_type: type \"" + std::string(name) +
|
||||||
|
"\" referenced unknown base type \"" + tname + "\"");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (default_holder != base_info->default_holder) {
|
||||||
|
std::string tname(base.name());
|
||||||
|
detail::clean_type_id(tname);
|
||||||
|
pybind11_fail("generic_type: type \"" + std::string(name) + "\" " +
|
||||||
|
(default_holder ? "does not have" : "has") +
|
||||||
|
" a non-default holder type while its base \"" + tname + "\" " +
|
||||||
|
(base_info->default_holder ? "does not" : "does"));
|
||||||
|
}
|
||||||
|
|
||||||
|
bases.append((PyObject *) base_info->type);
|
||||||
|
|
||||||
|
if (base_info->type->tp_dictoffset != 0)
|
||||||
|
dynamic_attr = true;
|
||||||
|
|
||||||
|
if (caster)
|
||||||
|
base_info->implicit_casts.emplace_back(type, caster);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
inline function_call::function_call(const function_record &f, handle p) :
|
||||||
|
func(f), parent(p) {
|
||||||
|
args.reserve(f.nargs);
|
||||||
|
args_convert.reserve(f.nargs);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Tag for a new-style `__init__` defined in `detail/init.h`
|
||||||
|
struct is_new_style_constructor { };
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Partial template specializations to process custom attributes provided to
|
||||||
|
* cpp_function_ and class_. These are either used to initialize the respective
|
||||||
|
* fields in the type_record and function_record data structures or executed at
|
||||||
|
* runtime to deal with custom call policies (e.g. keep_alive).
|
||||||
|
*/
|
||||||
|
template <typename T, typename SFINAE = void> struct process_attribute;
|
||||||
|
|
||||||
|
template <typename T> struct process_attribute_default {
|
||||||
|
/// Default implementation: do nothing
|
||||||
|
static void init(const T &, function_record *) { }
|
||||||
|
static void init(const T &, type_record *) { }
|
||||||
|
static void precall(function_call &) { }
|
||||||
|
static void postcall(function_call &, handle) { }
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Process an attribute specifying the function's name
|
||||||
|
template <> struct process_attribute<name> : process_attribute_default<name> {
|
||||||
|
static void init(const name &n, function_record *r) { r->name = const_cast<char *>(n.value); }
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Process an attribute specifying the function's docstring
|
||||||
|
template <> struct process_attribute<doc> : process_attribute_default<doc> {
|
||||||
|
static void init(const doc &n, function_record *r) { r->doc = const_cast<char *>(n.value); }
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Process an attribute specifying the function's docstring (provided as a C-style string)
|
||||||
|
template <> struct process_attribute<const char *> : process_attribute_default<const char *> {
|
||||||
|
static void init(const char *d, function_record *r) { r->doc = const_cast<char *>(d); }
|
||||||
|
static void init(const char *d, type_record *r) { r->doc = const_cast<char *>(d); }
|
||||||
|
};
|
||||||
|
template <> struct process_attribute<char *> : process_attribute<const char *> { };
|
||||||
|
|
||||||
|
/// Process an attribute indicating the function's return value policy
|
||||||
|
template <> struct process_attribute<return_value_policy> : process_attribute_default<return_value_policy> {
|
||||||
|
static void init(const return_value_policy &p, function_record *r) { r->policy = p; }
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Process an attribute which indicates that this is an overloaded function associated with a given sibling
|
||||||
|
template <> struct process_attribute<sibling> : process_attribute_default<sibling> {
|
||||||
|
static void init(const sibling &s, function_record *r) { r->sibling = s.value; }
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Process an attribute which indicates that this function is a method
|
||||||
|
template <> struct process_attribute<is_method> : process_attribute_default<is_method> {
|
||||||
|
static void init(const is_method &s, function_record *r) { r->is_method = true; r->scope = s.class_; }
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Process an attribute which indicates the parent scope of a method
|
||||||
|
template <> struct process_attribute<scope> : process_attribute_default<scope> {
|
||||||
|
static void init(const scope &s, function_record *r) { r->scope = s.value; }
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Process an attribute which indicates that this function is an operator
|
||||||
|
template <> struct process_attribute<is_operator> : process_attribute_default<is_operator> {
|
||||||
|
static void init(const is_operator &, function_record *r) { r->is_operator = true; }
|
||||||
|
};
|
||||||
|
|
||||||
|
template <> struct process_attribute<is_new_style_constructor> : process_attribute_default<is_new_style_constructor> {
|
||||||
|
static void init(const is_new_style_constructor &, function_record *r) { r->is_new_style_constructor = true; }
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Process a keyword argument attribute (*without* a default value)
|
||||||
|
template <> struct process_attribute<arg> : process_attribute_default<arg> {
|
||||||
|
static void init(const arg &a, function_record *r) {
|
||||||
|
if (r->is_method && r->args.empty())
|
||||||
|
r->args.emplace_back("self", nullptr, handle(), true /*convert*/, false /*none not allowed*/);
|
||||||
|
r->args.emplace_back(a.name, nullptr, handle(), !a.flag_noconvert, a.flag_none);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Process a keyword argument attribute (*with* a default value)
|
||||||
|
template <> struct process_attribute<arg_v> : process_attribute_default<arg_v> {
|
||||||
|
static void init(const arg_v &a, function_record *r) {
|
||||||
|
if (r->is_method && r->args.empty())
|
||||||
|
r->args.emplace_back("self", nullptr /*descr*/, handle() /*parent*/, true /*convert*/, false /*none not allowed*/);
|
||||||
|
|
||||||
|
if (!a.value) {
|
||||||
|
#if !defined(NDEBUG)
|
||||||
|
std::string descr("'");
|
||||||
|
if (a.name) descr += std::string(a.name) + ": ";
|
||||||
|
descr += a.type + "'";
|
||||||
|
if (r->is_method) {
|
||||||
|
if (r->name)
|
||||||
|
descr += " in method '" + (std::string) str(r->scope) + "." + (std::string) r->name + "'";
|
||||||
|
else
|
||||||
|
descr += " in method of '" + (std::string) str(r->scope) + "'";
|
||||||
|
} else if (r->name) {
|
||||||
|
descr += " in function '" + (std::string) r->name + "'";
|
||||||
|
}
|
||||||
|
pybind11_fail("arg(): could not convert default argument "
|
||||||
|
+ descr + " into a Python object (type not registered yet?)");
|
||||||
|
#else
|
||||||
|
pybind11_fail("arg(): could not convert default argument "
|
||||||
|
"into a Python object (type not registered yet?). "
|
||||||
|
"Compile in debug mode for more information.");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
r->args.emplace_back(a.name, a.descr, a.value.inc_ref(), !a.flag_noconvert, a.flag_none);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Process a parent class attribute. Single inheritance only (class_ itself already guarantees that)
|
||||||
|
template <typename T>
|
||||||
|
struct process_attribute<T, enable_if_t<is_pyobject<T>::value>> : process_attribute_default<handle> {
|
||||||
|
static void init(const handle &h, type_record *r) { r->bases.append(h); }
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Process a parent class attribute (deprecated, does not support multiple inheritance)
|
||||||
|
template <typename T>
|
||||||
|
struct process_attribute<base<T>> : process_attribute_default<base<T>> {
|
||||||
|
static void init(const base<T> &, type_record *r) { r->add_base(typeid(T), nullptr); }
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Process a multiple inheritance attribute
|
||||||
|
template <>
|
||||||
|
struct process_attribute<multiple_inheritance> : process_attribute_default<multiple_inheritance> {
|
||||||
|
static void init(const multiple_inheritance &, type_record *r) { r->multiple_inheritance = true; }
|
||||||
|
};
|
||||||
|
|
||||||
|
template <>
|
||||||
|
struct process_attribute<dynamic_attr> : process_attribute_default<dynamic_attr> {
|
||||||
|
static void init(const dynamic_attr &, type_record *r) { r->dynamic_attr = true; }
|
||||||
|
};
|
||||||
|
|
||||||
|
template <>
|
||||||
|
struct process_attribute<buffer_protocol> : process_attribute_default<buffer_protocol> {
|
||||||
|
static void init(const buffer_protocol &, type_record *r) { r->buffer_protocol = true; }
|
||||||
|
};
|
||||||
|
|
||||||
|
template <>
|
||||||
|
struct process_attribute<metaclass> : process_attribute_default<metaclass> {
|
||||||
|
static void init(const metaclass &m, type_record *r) { r->metaclass = m.value; }
|
||||||
|
};
|
||||||
|
|
||||||
|
template <>
|
||||||
|
struct process_attribute<module_local> : process_attribute_default<module_local> {
|
||||||
|
static void init(const module_local &l, type_record *r) { r->module_local = l.value; }
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Process an 'arithmetic' attribute for enums (does nothing here)
|
||||||
|
template <>
|
||||||
|
struct process_attribute<arithmetic> : process_attribute_default<arithmetic> {};
|
||||||
|
|
||||||
|
template <typename... Ts>
|
||||||
|
struct process_attribute<call_guard<Ts...>> : process_attribute_default<call_guard<Ts...>> { };
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Process a keep_alive call policy -- invokes keep_alive_impl during the
|
||||||
|
* pre-call handler if both Nurse, Patient != 0 and use the post-call handler
|
||||||
|
* otherwise
|
||||||
|
*/
|
||||||
|
template <size_t Nurse, size_t Patient> struct process_attribute<keep_alive<Nurse, Patient>> : public process_attribute_default<keep_alive<Nurse, Patient>> {
|
||||||
|
template <size_t N = Nurse, size_t P = Patient, enable_if_t<N != 0 && P != 0, int> = 0>
|
||||||
|
static void precall(function_call &call) { keep_alive_impl(Nurse, Patient, call, handle()); }
|
||||||
|
template <size_t N = Nurse, size_t P = Patient, enable_if_t<N != 0 && P != 0, int> = 0>
|
||||||
|
static void postcall(function_call &, handle) { }
|
||||||
|
template <size_t N = Nurse, size_t P = Patient, enable_if_t<N == 0 || P == 0, int> = 0>
|
||||||
|
static void precall(function_call &) { }
|
||||||
|
template <size_t N = Nurse, size_t P = Patient, enable_if_t<N == 0 || P == 0, int> = 0>
|
||||||
|
static void postcall(function_call &call, handle ret) { keep_alive_impl(Nurse, Patient, call, ret); }
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Recursively iterate over variadic template arguments
|
||||||
|
template <typename... Args> struct process_attributes {
|
||||||
|
static void init(const Args&... args, function_record *r) {
|
||||||
|
int unused[] = { 0, (process_attribute<typename std::decay<Args>::type>::init(args, r), 0) ... };
|
||||||
|
ignore_unused(unused);
|
||||||
|
}
|
||||||
|
static void init(const Args&... args, type_record *r) {
|
||||||
|
int unused[] = { 0, (process_attribute<typename std::decay<Args>::type>::init(args, r), 0) ... };
|
||||||
|
ignore_unused(unused);
|
||||||
|
}
|
||||||
|
static void precall(function_call &call) {
|
||||||
|
int unused[] = { 0, (process_attribute<typename std::decay<Args>::type>::precall(call), 0) ... };
|
||||||
|
ignore_unused(unused);
|
||||||
|
}
|
||||||
|
static void postcall(function_call &call, handle fn_ret) {
|
||||||
|
int unused[] = { 0, (process_attribute<typename std::decay<Args>::type>::postcall(call, fn_ret), 0) ... };
|
||||||
|
ignore_unused(unused);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
using is_call_guard = is_instantiation<call_guard, T>;
|
||||||
|
|
||||||
|
/// Extract the ``type`` from the first `call_guard` in `Extras...` (or `void_type` if none found)
|
||||||
|
template <typename... Extra>
|
||||||
|
using extract_guard_t = typename exactly_one_t<is_call_guard, call_guard<>, Extra...>::type;
|
||||||
|
|
||||||
|
/// Check the number of named arguments at compile time
|
||||||
|
template <typename... Extra,
|
||||||
|
size_t named = constexpr_sum(std::is_base_of<arg, Extra>::value...),
|
||||||
|
size_t self = constexpr_sum(std::is_same<is_method, Extra>::value...)>
|
||||||
|
constexpr bool expected_num_args(size_t nargs, bool has_args, bool has_kwargs) {
|
||||||
|
return named == 0 || (self + named + has_args + has_kwargs) == nargs;
|
||||||
|
}
|
||||||
|
|
||||||
|
NAMESPACE_END(detail)
|
||||||
|
NAMESPACE_END(PYBIND11_NAMESPACE)
|
114
3rdparty/pybind11/include/pybind11/buffer_info.h
vendored
Normal file
114
3rdparty/pybind11/include/pybind11/buffer_info.h
vendored
Normal file
@ -0,0 +1,114 @@
|
|||||||
|
/*
|
||||||
|
pybind11/buffer_info.h: Python buffer object interface
|
||||||
|
|
||||||
|
Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch>
|
||||||
|
|
||||||
|
All rights reserved. Use of this source code is governed by a
|
||||||
|
BSD-style license that can be found in the LICENSE file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "detail/common.h"
|
||||||
|
|
||||||
|
NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
|
||||||
|
|
||||||
|
/// Information record describing a Python buffer object
|
||||||
|
struct buffer_info {
|
||||||
|
void *ptr = nullptr; // Pointer to the underlying storage
|
||||||
|
ssize_t itemsize = 0; // Size of individual items in bytes
|
||||||
|
ssize_t size = 0; // Total number of entries
|
||||||
|
std::string format; // For homogeneous buffers, this should be set to format_descriptor<T>::format()
|
||||||
|
ssize_t ndim = 0; // Number of dimensions
|
||||||
|
std::vector<ssize_t> shape; // Shape of the tensor (1 entry per dimension)
|
||||||
|
std::vector<ssize_t> strides; // Number of bytes between adjacent entries (for each per dimension)
|
||||||
|
bool readonly = false; // flag to indicate if the underlying storage may be written to
|
||||||
|
|
||||||
|
buffer_info() { }
|
||||||
|
|
||||||
|
buffer_info(void *ptr, ssize_t itemsize, const std::string &format, ssize_t ndim,
|
||||||
|
detail::any_container<ssize_t> shape_in, detail::any_container<ssize_t> strides_in, bool readonly=false)
|
||||||
|
: ptr(ptr), itemsize(itemsize), size(1), format(format), ndim(ndim),
|
||||||
|
shape(std::move(shape_in)), strides(std::move(strides_in)), readonly(readonly) {
|
||||||
|
if (ndim != (ssize_t) shape.size() || ndim != (ssize_t) strides.size())
|
||||||
|
pybind11_fail("buffer_info: ndim doesn't match shape and/or strides length");
|
||||||
|
for (size_t i = 0; i < (size_t) ndim; ++i)
|
||||||
|
size *= shape[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
buffer_info(T *ptr, detail::any_container<ssize_t> shape_in, detail::any_container<ssize_t> strides_in, bool readonly=false)
|
||||||
|
: buffer_info(private_ctr_tag(), ptr, sizeof(T), format_descriptor<T>::format(), static_cast<ssize_t>(shape_in->size()), std::move(shape_in), std::move(strides_in), readonly) { }
|
||||||
|
|
||||||
|
buffer_info(void *ptr, ssize_t itemsize, const std::string &format, ssize_t size, bool readonly=false)
|
||||||
|
: buffer_info(ptr, itemsize, format, 1, {size}, {itemsize}, readonly) { }
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
buffer_info(T *ptr, ssize_t size, bool readonly=false)
|
||||||
|
: buffer_info(ptr, sizeof(T), format_descriptor<T>::format(), size, readonly) { }
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
buffer_info(const T *ptr, ssize_t size, bool readonly=true)
|
||||||
|
: buffer_info(const_cast<T*>(ptr), sizeof(T), format_descriptor<T>::format(), size, readonly) { }
|
||||||
|
|
||||||
|
explicit buffer_info(Py_buffer *view, bool ownview = true)
|
||||||
|
: buffer_info(view->buf, view->itemsize, view->format, view->ndim,
|
||||||
|
{view->shape, view->shape + view->ndim}, {view->strides, view->strides + view->ndim}, view->readonly) {
|
||||||
|
this->view = view;
|
||||||
|
this->ownview = ownview;
|
||||||
|
}
|
||||||
|
|
||||||
|
buffer_info(const buffer_info &) = delete;
|
||||||
|
buffer_info& operator=(const buffer_info &) = delete;
|
||||||
|
|
||||||
|
buffer_info(buffer_info &&other) {
|
||||||
|
(*this) = std::move(other);
|
||||||
|
}
|
||||||
|
|
||||||
|
buffer_info& operator=(buffer_info &&rhs) {
|
||||||
|
ptr = rhs.ptr;
|
||||||
|
itemsize = rhs.itemsize;
|
||||||
|
size = rhs.size;
|
||||||
|
format = std::move(rhs.format);
|
||||||
|
ndim = rhs.ndim;
|
||||||
|
shape = std::move(rhs.shape);
|
||||||
|
strides = std::move(rhs.strides);
|
||||||
|
std::swap(view, rhs.view);
|
||||||
|
std::swap(ownview, rhs.ownview);
|
||||||
|
readonly = rhs.readonly;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
~buffer_info() {
|
||||||
|
if (view && ownview) { PyBuffer_Release(view); delete view; }
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
struct private_ctr_tag { };
|
||||||
|
|
||||||
|
buffer_info(private_ctr_tag, void *ptr, ssize_t itemsize, const std::string &format, ssize_t ndim,
|
||||||
|
detail::any_container<ssize_t> &&shape_in, detail::any_container<ssize_t> &&strides_in, bool readonly)
|
||||||
|
: buffer_info(ptr, itemsize, format, ndim, std::move(shape_in), std::move(strides_in), readonly) { }
|
||||||
|
|
||||||
|
Py_buffer *view = nullptr;
|
||||||
|
bool ownview = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
NAMESPACE_BEGIN(detail)
|
||||||
|
|
||||||
|
template <typename T, typename SFINAE = void> struct compare_buffer_info {
|
||||||
|
static bool compare(const buffer_info& b) {
|
||||||
|
return b.format == format_descriptor<T>::format() && b.itemsize == (ssize_t) sizeof(T);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T> struct compare_buffer_info<T, detail::enable_if_t<std::is_integral<T>::value>> {
|
||||||
|
static bool compare(const buffer_info& b) {
|
||||||
|
return (size_t) b.itemsize == sizeof(T) && (b.format == format_descriptor<T>::value ||
|
||||||
|
((sizeof(T) == sizeof(long)) && b.format == (std::is_unsigned<T>::value ? "L" : "l")) ||
|
||||||
|
((sizeof(T) == sizeof(size_t)) && b.format == (std::is_unsigned<T>::value ? "N" : "n")));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
NAMESPACE_END(detail)
|
||||||
|
NAMESPACE_END(PYBIND11_NAMESPACE)
|
2179
3rdparty/pybind11/include/pybind11/cast.h
vendored
Normal file
2179
3rdparty/pybind11/include/pybind11/cast.h
vendored
Normal file
File diff suppressed because it is too large
Load Diff
184
3rdparty/pybind11/include/pybind11/chrono.h
vendored
Normal file
184
3rdparty/pybind11/include/pybind11/chrono.h
vendored
Normal file
@ -0,0 +1,184 @@
|
|||||||
|
/*
|
||||||
|
pybind11/chrono.h: Transparent conversion between std::chrono and python's datetime
|
||||||
|
|
||||||
|
Copyright (c) 2016 Trent Houliston <trent@houliston.me> and
|
||||||
|
Wenzel Jakob <wenzel.jakob@epfl.ch>
|
||||||
|
|
||||||
|
All rights reserved. Use of this source code is governed by a
|
||||||
|
BSD-style license that can be found in the LICENSE file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "pybind11.h"
|
||||||
|
#include <cmath>
|
||||||
|
#include <ctime>
|
||||||
|
#include <chrono>
|
||||||
|
#include <datetime.h>
|
||||||
|
|
||||||
|
// Backport the PyDateTime_DELTA functions from Python3.3 if required
|
||||||
|
#ifndef PyDateTime_DELTA_GET_DAYS
|
||||||
|
#define PyDateTime_DELTA_GET_DAYS(o) (((PyDateTime_Delta*)o)->days)
|
||||||
|
#endif
|
||||||
|
#ifndef PyDateTime_DELTA_GET_SECONDS
|
||||||
|
#define PyDateTime_DELTA_GET_SECONDS(o) (((PyDateTime_Delta*)o)->seconds)
|
||||||
|
#endif
|
||||||
|
#ifndef PyDateTime_DELTA_GET_MICROSECONDS
|
||||||
|
#define PyDateTime_DELTA_GET_MICROSECONDS(o) (((PyDateTime_Delta*)o)->microseconds)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
|
||||||
|
NAMESPACE_BEGIN(detail)
|
||||||
|
|
||||||
|
template <typename type> class duration_caster {
|
||||||
|
public:
|
||||||
|
typedef typename type::rep rep;
|
||||||
|
typedef typename type::period period;
|
||||||
|
|
||||||
|
typedef std::chrono::duration<uint_fast32_t, std::ratio<86400>> days;
|
||||||
|
|
||||||
|
bool load(handle src, bool) {
|
||||||
|
using namespace std::chrono;
|
||||||
|
|
||||||
|
// Lazy initialise the PyDateTime import
|
||||||
|
if (!PyDateTimeAPI) { PyDateTime_IMPORT; }
|
||||||
|
|
||||||
|
if (!src) return false;
|
||||||
|
// If invoked with datetime.delta object
|
||||||
|
if (PyDelta_Check(src.ptr())) {
|
||||||
|
value = type(duration_cast<duration<rep, period>>(
|
||||||
|
days(PyDateTime_DELTA_GET_DAYS(src.ptr()))
|
||||||
|
+ seconds(PyDateTime_DELTA_GET_SECONDS(src.ptr()))
|
||||||
|
+ microseconds(PyDateTime_DELTA_GET_MICROSECONDS(src.ptr()))));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
// If invoked with a float we assume it is seconds and convert
|
||||||
|
else if (PyFloat_Check(src.ptr())) {
|
||||||
|
value = type(duration_cast<duration<rep, period>>(duration<double>(PyFloat_AsDouble(src.ptr()))));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If this is a duration just return it back
|
||||||
|
static const std::chrono::duration<rep, period>& get_duration(const std::chrono::duration<rep, period> &src) {
|
||||||
|
return src;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If this is a time_point get the time_since_epoch
|
||||||
|
template <typename Clock> static std::chrono::duration<rep, period> get_duration(const std::chrono::time_point<Clock, std::chrono::duration<rep, period>> &src) {
|
||||||
|
return src.time_since_epoch();
|
||||||
|
}
|
||||||
|
|
||||||
|
static handle cast(const type &src, return_value_policy /* policy */, handle /* parent */) {
|
||||||
|
using namespace std::chrono;
|
||||||
|
|
||||||
|
// Use overloaded function to get our duration from our source
|
||||||
|
// Works out if it is a duration or time_point and get the duration
|
||||||
|
auto d = get_duration(src);
|
||||||
|
|
||||||
|
// Lazy initialise the PyDateTime import
|
||||||
|
if (!PyDateTimeAPI) { PyDateTime_IMPORT; }
|
||||||
|
|
||||||
|
// Declare these special duration types so the conversions happen with the correct primitive types (int)
|
||||||
|
using dd_t = duration<int, std::ratio<86400>>;
|
||||||
|
using ss_t = duration<int, std::ratio<1>>;
|
||||||
|
using us_t = duration<int, std::micro>;
|
||||||
|
|
||||||
|
auto dd = duration_cast<dd_t>(d);
|
||||||
|
auto subd = d - dd;
|
||||||
|
auto ss = duration_cast<ss_t>(subd);
|
||||||
|
auto us = duration_cast<us_t>(subd - ss);
|
||||||
|
return PyDelta_FromDSU(dd.count(), ss.count(), us.count());
|
||||||
|
}
|
||||||
|
|
||||||
|
PYBIND11_TYPE_CASTER(type, _("datetime.timedelta"));
|
||||||
|
};
|
||||||
|
|
||||||
|
// This is for casting times on the system clock into datetime.datetime instances
|
||||||
|
template <typename Duration> class type_caster<std::chrono::time_point<std::chrono::system_clock, Duration>> {
|
||||||
|
public:
|
||||||
|
typedef std::chrono::time_point<std::chrono::system_clock, Duration> type;
|
||||||
|
bool load(handle src, bool) {
|
||||||
|
using namespace std::chrono;
|
||||||
|
|
||||||
|
// Lazy initialise the PyDateTime import
|
||||||
|
if (!PyDateTimeAPI) { PyDateTime_IMPORT; }
|
||||||
|
|
||||||
|
if (!src) return false;
|
||||||
|
|
||||||
|
std::tm cal;
|
||||||
|
microseconds msecs;
|
||||||
|
|
||||||
|
if (PyDateTime_Check(src.ptr())) {
|
||||||
|
cal.tm_sec = PyDateTime_DATE_GET_SECOND(src.ptr());
|
||||||
|
cal.tm_min = PyDateTime_DATE_GET_MINUTE(src.ptr());
|
||||||
|
cal.tm_hour = PyDateTime_DATE_GET_HOUR(src.ptr());
|
||||||
|
cal.tm_mday = PyDateTime_GET_DAY(src.ptr());
|
||||||
|
cal.tm_mon = PyDateTime_GET_MONTH(src.ptr()) - 1;
|
||||||
|
cal.tm_year = PyDateTime_GET_YEAR(src.ptr()) - 1900;
|
||||||
|
cal.tm_isdst = -1;
|
||||||
|
msecs = microseconds(PyDateTime_DATE_GET_MICROSECOND(src.ptr()));
|
||||||
|
} else if (PyDate_Check(src.ptr())) {
|
||||||
|
cal.tm_sec = 0;
|
||||||
|
cal.tm_min = 0;
|
||||||
|
cal.tm_hour = 0;
|
||||||
|
cal.tm_mday = PyDateTime_GET_DAY(src.ptr());
|
||||||
|
cal.tm_mon = PyDateTime_GET_MONTH(src.ptr()) - 1;
|
||||||
|
cal.tm_year = PyDateTime_GET_YEAR(src.ptr()) - 1900;
|
||||||
|
cal.tm_isdst = -1;
|
||||||
|
msecs = microseconds(0);
|
||||||
|
} else if (PyTime_Check(src.ptr())) {
|
||||||
|
cal.tm_sec = PyDateTime_TIME_GET_SECOND(src.ptr());
|
||||||
|
cal.tm_min = PyDateTime_TIME_GET_MINUTE(src.ptr());
|
||||||
|
cal.tm_hour = PyDateTime_TIME_GET_HOUR(src.ptr());
|
||||||
|
cal.tm_mday = 1; // This date (day, month, year) = (1, 0, 70)
|
||||||
|
cal.tm_mon = 0; // represents 1-Jan-1970, which is the first
|
||||||
|
cal.tm_year = 70; // earliest available date for Python's datetime
|
||||||
|
cal.tm_isdst = -1;
|
||||||
|
msecs = microseconds(PyDateTime_TIME_GET_MICROSECOND(src.ptr()));
|
||||||
|
}
|
||||||
|
else return false;
|
||||||
|
|
||||||
|
value = system_clock::from_time_t(std::mktime(&cal)) + msecs;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static handle cast(const std::chrono::time_point<std::chrono::system_clock, Duration> &src, return_value_policy /* policy */, handle /* parent */) {
|
||||||
|
using namespace std::chrono;
|
||||||
|
|
||||||
|
// Lazy initialise the PyDateTime import
|
||||||
|
if (!PyDateTimeAPI) { PyDateTime_IMPORT; }
|
||||||
|
|
||||||
|
std::time_t tt = system_clock::to_time_t(time_point_cast<system_clock::duration>(src));
|
||||||
|
// this function uses static memory so it's best to copy it out asap just in case
|
||||||
|
// otherwise other code that is using localtime may break this (not just python code)
|
||||||
|
std::tm localtime = *std::localtime(&tt);
|
||||||
|
|
||||||
|
// Declare these special duration types so the conversions happen with the correct primitive types (int)
|
||||||
|
using us_t = duration<int, std::micro>;
|
||||||
|
|
||||||
|
return PyDateTime_FromDateAndTime(localtime.tm_year + 1900,
|
||||||
|
localtime.tm_mon + 1,
|
||||||
|
localtime.tm_mday,
|
||||||
|
localtime.tm_hour,
|
||||||
|
localtime.tm_min,
|
||||||
|
localtime.tm_sec,
|
||||||
|
(duration_cast<us_t>(src.time_since_epoch() % seconds(1))).count());
|
||||||
|
}
|
||||||
|
PYBIND11_TYPE_CASTER(type, _("datetime.datetime"));
|
||||||
|
};
|
||||||
|
|
||||||
|
// Other clocks that are not the system clock are not measured as datetime.datetime objects
|
||||||
|
// since they are not measured on calendar time. So instead we just make them timedeltas
|
||||||
|
// Or if they have passed us a time as a float we convert that
|
||||||
|
template <typename Clock, typename Duration> class type_caster<std::chrono::time_point<Clock, Duration>>
|
||||||
|
: public duration_caster<std::chrono::time_point<Clock, Duration>> {
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename Rep, typename Period> class type_caster<std::chrono::duration<Rep, Period>>
|
||||||
|
: public duration_caster<std::chrono::duration<Rep, Period>> {
|
||||||
|
};
|
||||||
|
|
||||||
|
NAMESPACE_END(detail)
|
||||||
|
NAMESPACE_END(PYBIND11_NAMESPACE)
|
2
3rdparty/pybind11/include/pybind11/common.h
vendored
Normal file
2
3rdparty/pybind11/include/pybind11/common.h
vendored
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
#include "detail/common.h"
|
||||||
|
#warning "Including 'common.h' is deprecated. It will be removed in v3.0. Use 'pybind11.h'."
|
65
3rdparty/pybind11/include/pybind11/complex.h
vendored
Normal file
65
3rdparty/pybind11/include/pybind11/complex.h
vendored
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
/*
|
||||||
|
pybind11/complex.h: Complex number support
|
||||||
|
|
||||||
|
Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch>
|
||||||
|
|
||||||
|
All rights reserved. Use of this source code is governed by a
|
||||||
|
BSD-style license that can be found in the LICENSE file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "pybind11.h"
|
||||||
|
#include <complex>
|
||||||
|
|
||||||
|
/// glibc defines I as a macro which breaks things, e.g., boost template names
|
||||||
|
#ifdef I
|
||||||
|
# undef I
|
||||||
|
#endif
|
||||||
|
|
||||||
|
NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
|
||||||
|
|
||||||
|
template <typename T> struct format_descriptor<std::complex<T>, detail::enable_if_t<std::is_floating_point<T>::value>> {
|
||||||
|
static constexpr const char c = format_descriptor<T>::c;
|
||||||
|
static constexpr const char value[3] = { 'Z', c, '\0' };
|
||||||
|
static std::string format() { return std::string(value); }
|
||||||
|
};
|
||||||
|
|
||||||
|
#ifndef PYBIND11_CPP17
|
||||||
|
|
||||||
|
template <typename T> constexpr const char format_descriptor<
|
||||||
|
std::complex<T>, detail::enable_if_t<std::is_floating_point<T>::value>>::value[3];
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
NAMESPACE_BEGIN(detail)
|
||||||
|
|
||||||
|
template <typename T> struct is_fmt_numeric<std::complex<T>, detail::enable_if_t<std::is_floating_point<T>::value>> {
|
||||||
|
static constexpr bool value = true;
|
||||||
|
static constexpr int index = is_fmt_numeric<T>::index + 3;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T> class type_caster<std::complex<T>> {
|
||||||
|
public:
|
||||||
|
bool load(handle src, bool convert) {
|
||||||
|
if (!src)
|
||||||
|
return false;
|
||||||
|
if (!convert && !PyComplex_Check(src.ptr()))
|
||||||
|
return false;
|
||||||
|
Py_complex result = PyComplex_AsCComplex(src.ptr());
|
||||||
|
if (result.real == -1.0 && PyErr_Occurred()) {
|
||||||
|
PyErr_Clear();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
value = std::complex<T>((T) result.real, (T) result.imag);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static handle cast(const std::complex<T> &src, return_value_policy /* policy */, handle /* parent */) {
|
||||||
|
return PyComplex_FromDoubles((double) src.real(), (double) src.imag());
|
||||||
|
}
|
||||||
|
|
||||||
|
PYBIND11_TYPE_CASTER(std::complex<T>, _("complex"));
|
||||||
|
};
|
||||||
|
NAMESPACE_END(detail)
|
||||||
|
NAMESPACE_END(PYBIND11_NAMESPACE)
|
639
3rdparty/pybind11/include/pybind11/detail/class.h
vendored
Normal file
639
3rdparty/pybind11/include/pybind11/detail/class.h
vendored
Normal file
@ -0,0 +1,639 @@
|
|||||||
|
/*
|
||||||
|
pybind11/detail/class.h: Python C API implementation details for py::class_
|
||||||
|
|
||||||
|
Copyright (c) 2017 Wenzel Jakob <wenzel.jakob@epfl.ch>
|
||||||
|
|
||||||
|
All rights reserved. Use of this source code is governed by a
|
||||||
|
BSD-style license that can be found in the LICENSE file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "../attr.h"
|
||||||
|
#include "../options.h"
|
||||||
|
|
||||||
|
NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
|
||||||
|
NAMESPACE_BEGIN(detail)
|
||||||
|
|
||||||
|
#if PY_VERSION_HEX >= 0x03030000
|
||||||
|
# define PYBIND11_BUILTIN_QUALNAME
|
||||||
|
# define PYBIND11_SET_OLDPY_QUALNAME(obj, nameobj)
|
||||||
|
#else
|
||||||
|
// In pre-3.3 Python, we still set __qualname__ so that we can produce reliable function type
|
||||||
|
// signatures; in 3.3+ this macro expands to nothing:
|
||||||
|
# define PYBIND11_SET_OLDPY_QUALNAME(obj, nameobj) setattr((PyObject *) obj, "__qualname__", nameobj)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
inline PyTypeObject *type_incref(PyTypeObject *type) {
|
||||||
|
Py_INCREF(type);
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if !defined(PYPY_VERSION)
|
||||||
|
|
||||||
|
/// `pybind11_static_property.__get__()`: Always pass the class instead of the instance.
|
||||||
|
extern "C" inline PyObject *pybind11_static_get(PyObject *self, PyObject * /*ob*/, PyObject *cls) {
|
||||||
|
return PyProperty_Type.tp_descr_get(self, cls, cls);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// `pybind11_static_property.__set__()`: Just like the above `__get__()`.
|
||||||
|
extern "C" inline int pybind11_static_set(PyObject *self, PyObject *obj, PyObject *value) {
|
||||||
|
PyObject *cls = PyType_Check(obj) ? obj : (PyObject *) Py_TYPE(obj);
|
||||||
|
return PyProperty_Type.tp_descr_set(self, cls, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** A `static_property` is the same as a `property` but the `__get__()` and `__set__()`
|
||||||
|
methods are modified to always use the object type instead of a concrete instance.
|
||||||
|
Return value: New reference. */
|
||||||
|
inline PyTypeObject *make_static_property_type() {
|
||||||
|
constexpr auto *name = "pybind11_static_property";
|
||||||
|
auto name_obj = reinterpret_steal<object>(PYBIND11_FROM_STRING(name));
|
||||||
|
|
||||||
|
/* Danger zone: from now (and until PyType_Ready), make sure to
|
||||||
|
issue no Python C API calls which could potentially invoke the
|
||||||
|
garbage collector (the GC will call type_traverse(), which will in
|
||||||
|
turn find the newly constructed type in an invalid state) */
|
||||||
|
auto heap_type = (PyHeapTypeObject *) PyType_Type.tp_alloc(&PyType_Type, 0);
|
||||||
|
if (!heap_type)
|
||||||
|
pybind11_fail("make_static_property_type(): error allocating type!");
|
||||||
|
|
||||||
|
heap_type->ht_name = name_obj.inc_ref().ptr();
|
||||||
|
#ifdef PYBIND11_BUILTIN_QUALNAME
|
||||||
|
heap_type->ht_qualname = name_obj.inc_ref().ptr();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
auto type = &heap_type->ht_type;
|
||||||
|
type->tp_name = name;
|
||||||
|
type->tp_base = type_incref(&PyProperty_Type);
|
||||||
|
type->tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HEAPTYPE;
|
||||||
|
type->tp_descr_get = pybind11_static_get;
|
||||||
|
type->tp_descr_set = pybind11_static_set;
|
||||||
|
|
||||||
|
if (PyType_Ready(type) < 0)
|
||||||
|
pybind11_fail("make_static_property_type(): failure in PyType_Ready()!");
|
||||||
|
|
||||||
|
setattr((PyObject *) type, "__module__", str("pybind11_builtins"));
|
||||||
|
PYBIND11_SET_OLDPY_QUALNAME(type, name_obj);
|
||||||
|
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
|
||||||
|
#else // PYPY
|
||||||
|
|
||||||
|
/** PyPy has some issues with the above C API, so we evaluate Python code instead.
|
||||||
|
This function will only be called once so performance isn't really a concern.
|
||||||
|
Return value: New reference. */
|
||||||
|
inline PyTypeObject *make_static_property_type() {
|
||||||
|
auto d = dict();
|
||||||
|
PyObject *result = PyRun_String(R"(\
|
||||||
|
class pybind11_static_property(property):
|
||||||
|
def __get__(self, obj, cls):
|
||||||
|
return property.__get__(self, cls, cls)
|
||||||
|
|
||||||
|
def __set__(self, obj, value):
|
||||||
|
cls = obj if isinstance(obj, type) else type(obj)
|
||||||
|
property.__set__(self, cls, value)
|
||||||
|
)", Py_file_input, d.ptr(), d.ptr()
|
||||||
|
);
|
||||||
|
if (result == nullptr)
|
||||||
|
throw error_already_set();
|
||||||
|
Py_DECREF(result);
|
||||||
|
return (PyTypeObject *) d["pybind11_static_property"].cast<object>().release().ptr();
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // PYPY
|
||||||
|
|
||||||
|
/** Types with static properties need to handle `Type.static_prop = x` in a specific way.
|
||||||
|
By default, Python replaces the `static_property` itself, but for wrapped C++ types
|
||||||
|
we need to call `static_property.__set__()` in order to propagate the new value to
|
||||||
|
the underlying C++ data structure. */
|
||||||
|
extern "C" inline int pybind11_meta_setattro(PyObject* obj, PyObject* name, PyObject* value) {
|
||||||
|
// Use `_PyType_Lookup()` instead of `PyObject_GetAttr()` in order to get the raw
|
||||||
|
// descriptor (`property`) instead of calling `tp_descr_get` (`property.__get__()`).
|
||||||
|
PyObject *descr = _PyType_Lookup((PyTypeObject *) obj, name);
|
||||||
|
|
||||||
|
// The following assignment combinations are possible:
|
||||||
|
// 1. `Type.static_prop = value` --> descr_set: `Type.static_prop.__set__(value)`
|
||||||
|
// 2. `Type.static_prop = other_static_prop` --> setattro: replace existing `static_prop`
|
||||||
|
// 3. `Type.regular_attribute = value` --> setattro: regular attribute assignment
|
||||||
|
const auto static_prop = (PyObject *) get_internals().static_property_type;
|
||||||
|
const auto call_descr_set = descr && PyObject_IsInstance(descr, static_prop)
|
||||||
|
&& !PyObject_IsInstance(value, static_prop);
|
||||||
|
if (call_descr_set) {
|
||||||
|
// Call `static_property.__set__()` instead of replacing the `static_property`.
|
||||||
|
#if !defined(PYPY_VERSION)
|
||||||
|
return Py_TYPE(descr)->tp_descr_set(descr, obj, value);
|
||||||
|
#else
|
||||||
|
if (PyObject *result = PyObject_CallMethod(descr, "__set__", "OO", obj, value)) {
|
||||||
|
Py_DECREF(result);
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
} else {
|
||||||
|
// Replace existing attribute.
|
||||||
|
return PyType_Type.tp_setattro(obj, name, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#if PY_MAJOR_VERSION >= 3
|
||||||
|
/**
|
||||||
|
* Python 3's PyInstanceMethod_Type hides itself via its tp_descr_get, which prevents aliasing
|
||||||
|
* methods via cls.attr("m2") = cls.attr("m1"): instead the tp_descr_get returns a plain function,
|
||||||
|
* when called on a class, or a PyMethod, when called on an instance. Override that behaviour here
|
||||||
|
* to do a special case bypass for PyInstanceMethod_Types.
|
||||||
|
*/
|
||||||
|
extern "C" inline PyObject *pybind11_meta_getattro(PyObject *obj, PyObject *name) {
|
||||||
|
PyObject *descr = _PyType_Lookup((PyTypeObject *) obj, name);
|
||||||
|
if (descr && PyInstanceMethod_Check(descr)) {
|
||||||
|
Py_INCREF(descr);
|
||||||
|
return descr;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return PyType_Type.tp_getattro(obj, name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/** This metaclass is assigned by default to all pybind11 types and is required in order
|
||||||
|
for static properties to function correctly. Users may override this using `py::metaclass`.
|
||||||
|
Return value: New reference. */
|
||||||
|
inline PyTypeObject* make_default_metaclass() {
|
||||||
|
constexpr auto *name = "pybind11_type";
|
||||||
|
auto name_obj = reinterpret_steal<object>(PYBIND11_FROM_STRING(name));
|
||||||
|
|
||||||
|
/* Danger zone: from now (and until PyType_Ready), make sure to
|
||||||
|
issue no Python C API calls which could potentially invoke the
|
||||||
|
garbage collector (the GC will call type_traverse(), which will in
|
||||||
|
turn find the newly constructed type in an invalid state) */
|
||||||
|
auto heap_type = (PyHeapTypeObject *) PyType_Type.tp_alloc(&PyType_Type, 0);
|
||||||
|
if (!heap_type)
|
||||||
|
pybind11_fail("make_default_metaclass(): error allocating metaclass!");
|
||||||
|
|
||||||
|
heap_type->ht_name = name_obj.inc_ref().ptr();
|
||||||
|
#ifdef PYBIND11_BUILTIN_QUALNAME
|
||||||
|
heap_type->ht_qualname = name_obj.inc_ref().ptr();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
auto type = &heap_type->ht_type;
|
||||||
|
type->tp_name = name;
|
||||||
|
type->tp_base = type_incref(&PyType_Type);
|
||||||
|
type->tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HEAPTYPE;
|
||||||
|
|
||||||
|
type->tp_setattro = pybind11_meta_setattro;
|
||||||
|
#if PY_MAJOR_VERSION >= 3
|
||||||
|
type->tp_getattro = pybind11_meta_getattro;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (PyType_Ready(type) < 0)
|
||||||
|
pybind11_fail("make_default_metaclass(): failure in PyType_Ready()!");
|
||||||
|
|
||||||
|
setattr((PyObject *) type, "__module__", str("pybind11_builtins"));
|
||||||
|
PYBIND11_SET_OLDPY_QUALNAME(type, name_obj);
|
||||||
|
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// For multiple inheritance types we need to recursively register/deregister base pointers for any
|
||||||
|
/// base classes with pointers that are difference from the instance value pointer so that we can
|
||||||
|
/// correctly recognize an offset base class pointer. This calls a function with any offset base ptrs.
|
||||||
|
inline void traverse_offset_bases(void *valueptr, const detail::type_info *tinfo, instance *self,
|
||||||
|
bool (*f)(void * /*parentptr*/, instance * /*self*/)) {
|
||||||
|
for (handle h : reinterpret_borrow<tuple>(tinfo->type->tp_bases)) {
|
||||||
|
if (auto parent_tinfo = get_type_info((PyTypeObject *) h.ptr())) {
|
||||||
|
for (auto &c : parent_tinfo->implicit_casts) {
|
||||||
|
if (c.first == tinfo->cpptype) {
|
||||||
|
auto *parentptr = c.second(valueptr);
|
||||||
|
if (parentptr != valueptr)
|
||||||
|
f(parentptr, self);
|
||||||
|
traverse_offset_bases(parentptr, parent_tinfo, self, f);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool register_instance_impl(void *ptr, instance *self) {
|
||||||
|
get_internals().registered_instances.emplace(ptr, self);
|
||||||
|
return true; // unused, but gives the same signature as the deregister func
|
||||||
|
}
|
||||||
|
inline bool deregister_instance_impl(void *ptr, instance *self) {
|
||||||
|
auto ®istered_instances = get_internals().registered_instances;
|
||||||
|
auto range = registered_instances.equal_range(ptr);
|
||||||
|
for (auto it = range.first; it != range.second; ++it) {
|
||||||
|
if (Py_TYPE(self) == Py_TYPE(it->second)) {
|
||||||
|
registered_instances.erase(it);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void register_instance(instance *self, void *valptr, const type_info *tinfo) {
|
||||||
|
register_instance_impl(valptr, self);
|
||||||
|
if (!tinfo->simple_ancestors)
|
||||||
|
traverse_offset_bases(valptr, tinfo, self, register_instance_impl);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool deregister_instance(instance *self, void *valptr, const type_info *tinfo) {
|
||||||
|
bool ret = deregister_instance_impl(valptr, self);
|
||||||
|
if (!tinfo->simple_ancestors)
|
||||||
|
traverse_offset_bases(valptr, tinfo, self, deregister_instance_impl);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Instance creation function for all pybind11 types. It allocates the internal instance layout for
|
||||||
|
/// holding C++ objects and holders. Allocation is done lazily (the first time the instance is cast
|
||||||
|
/// to a reference or pointer), and initialization is done by an `__init__` function.
|
||||||
|
inline PyObject *make_new_instance(PyTypeObject *type) {
|
||||||
|
#if defined(PYPY_VERSION)
|
||||||
|
// PyPy gets tp_basicsize wrong (issue 2482) under multiple inheritance when the first inherited
|
||||||
|
// object is a a plain Python type (i.e. not derived from an extension type). Fix it.
|
||||||
|
ssize_t instance_size = static_cast<ssize_t>(sizeof(instance));
|
||||||
|
if (type->tp_basicsize < instance_size) {
|
||||||
|
type->tp_basicsize = instance_size;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
PyObject *self = type->tp_alloc(type, 0);
|
||||||
|
auto inst = reinterpret_cast<instance *>(self);
|
||||||
|
// Allocate the value/holder internals:
|
||||||
|
inst->allocate_layout();
|
||||||
|
|
||||||
|
inst->owned = true;
|
||||||
|
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Instance creation function for all pybind11 types. It only allocates space for the
|
||||||
|
/// C++ object, but doesn't call the constructor -- an `__init__` function must do that.
|
||||||
|
extern "C" inline PyObject *pybind11_object_new(PyTypeObject *type, PyObject *, PyObject *) {
|
||||||
|
return make_new_instance(type);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// An `__init__` function constructs the C++ object. Users should provide at least one
|
||||||
|
/// of these using `py::init` or directly with `.def(__init__, ...)`. Otherwise, the
|
||||||
|
/// following default function will be used which simply throws an exception.
|
||||||
|
extern "C" inline int pybind11_object_init(PyObject *self, PyObject *, PyObject *) {
|
||||||
|
PyTypeObject *type = Py_TYPE(self);
|
||||||
|
std::string msg;
|
||||||
|
#if defined(PYPY_VERSION)
|
||||||
|
msg += handle((PyObject *) type).attr("__module__").cast<std::string>() + ".";
|
||||||
|
#endif
|
||||||
|
msg += type->tp_name;
|
||||||
|
msg += ": No constructor defined!";
|
||||||
|
PyErr_SetString(PyExc_TypeError, msg.c_str());
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void add_patient(PyObject *nurse, PyObject *patient) {
|
||||||
|
auto &internals = get_internals();
|
||||||
|
auto instance = reinterpret_cast<detail::instance *>(nurse);
|
||||||
|
instance->has_patients = true;
|
||||||
|
Py_INCREF(patient);
|
||||||
|
internals.patients[nurse].push_back(patient);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void clear_patients(PyObject *self) {
|
||||||
|
auto instance = reinterpret_cast<detail::instance *>(self);
|
||||||
|
auto &internals = get_internals();
|
||||||
|
auto pos = internals.patients.find(self);
|
||||||
|
assert(pos != internals.patients.end());
|
||||||
|
// Clearing the patients can cause more Python code to run, which
|
||||||
|
// can invalidate the iterator. Extract the vector of patients
|
||||||
|
// from the unordered_map first.
|
||||||
|
auto patients = std::move(pos->second);
|
||||||
|
internals.patients.erase(pos);
|
||||||
|
instance->has_patients = false;
|
||||||
|
for (PyObject *&patient : patients)
|
||||||
|
Py_CLEAR(patient);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Clears all internal data from the instance and removes it from registered instances in
|
||||||
|
/// preparation for deallocation.
|
||||||
|
inline void clear_instance(PyObject *self) {
|
||||||
|
auto instance = reinterpret_cast<detail::instance *>(self);
|
||||||
|
|
||||||
|
// Deallocate any values/holders, if present:
|
||||||
|
for (auto &v_h : values_and_holders(instance)) {
|
||||||
|
if (v_h) {
|
||||||
|
|
||||||
|
// We have to deregister before we call dealloc because, for virtual MI types, we still
|
||||||
|
// need to be able to get the parent pointers.
|
||||||
|
if (v_h.instance_registered() && !deregister_instance(instance, v_h.value_ptr(), v_h.type))
|
||||||
|
pybind11_fail("pybind11_object_dealloc(): Tried to deallocate unregistered instance!");
|
||||||
|
|
||||||
|
if (instance->owned || v_h.holder_constructed())
|
||||||
|
v_h.type->dealloc(v_h);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Deallocate the value/holder layout internals:
|
||||||
|
instance->deallocate_layout();
|
||||||
|
|
||||||
|
if (instance->weakrefs)
|
||||||
|
PyObject_ClearWeakRefs(self);
|
||||||
|
|
||||||
|
PyObject **dict_ptr = _PyObject_GetDictPtr(self);
|
||||||
|
if (dict_ptr)
|
||||||
|
Py_CLEAR(*dict_ptr);
|
||||||
|
|
||||||
|
if (instance->has_patients)
|
||||||
|
clear_patients(self);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Instance destructor function for all pybind11 types. It calls `type_info.dealloc`
|
||||||
|
/// to destroy the C++ object itself, while the rest is Python bookkeeping.
|
||||||
|
extern "C" inline void pybind11_object_dealloc(PyObject *self) {
|
||||||
|
clear_instance(self);
|
||||||
|
|
||||||
|
auto type = Py_TYPE(self);
|
||||||
|
type->tp_free(self);
|
||||||
|
|
||||||
|
#if PY_VERSION_HEX < 0x03080000
|
||||||
|
// `type->tp_dealloc != pybind11_object_dealloc` means that we're being called
|
||||||
|
// as part of a derived type's dealloc, in which case we're not allowed to decref
|
||||||
|
// the type here. For cross-module compatibility, we shouldn't compare directly
|
||||||
|
// with `pybind11_object_dealloc`, but with the common one stashed in internals.
|
||||||
|
auto pybind11_object_type = (PyTypeObject *) get_internals().instance_base;
|
||||||
|
if (type->tp_dealloc == pybind11_object_type->tp_dealloc)
|
||||||
|
Py_DECREF(type);
|
||||||
|
#else
|
||||||
|
// This was not needed before Python 3.8 (Python issue 35810)
|
||||||
|
// https://github.com/pybind/pybind11/issues/1946
|
||||||
|
Py_DECREF(type);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Create the type which can be used as a common base for all classes. This is
|
||||||
|
needed in order to satisfy Python's requirements for multiple inheritance.
|
||||||
|
Return value: New reference. */
|
||||||
|
inline PyObject *make_object_base_type(PyTypeObject *metaclass) {
|
||||||
|
constexpr auto *name = "pybind11_object";
|
||||||
|
auto name_obj = reinterpret_steal<object>(PYBIND11_FROM_STRING(name));
|
||||||
|
|
||||||
|
/* Danger zone: from now (and until PyType_Ready), make sure to
|
||||||
|
issue no Python C API calls which could potentially invoke the
|
||||||
|
garbage collector (the GC will call type_traverse(), which will in
|
||||||
|
turn find the newly constructed type in an invalid state) */
|
||||||
|
auto heap_type = (PyHeapTypeObject *) metaclass->tp_alloc(metaclass, 0);
|
||||||
|
if (!heap_type)
|
||||||
|
pybind11_fail("make_object_base_type(): error allocating type!");
|
||||||
|
|
||||||
|
heap_type->ht_name = name_obj.inc_ref().ptr();
|
||||||
|
#ifdef PYBIND11_BUILTIN_QUALNAME
|
||||||
|
heap_type->ht_qualname = name_obj.inc_ref().ptr();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
auto type = &heap_type->ht_type;
|
||||||
|
type->tp_name = name;
|
||||||
|
type->tp_base = type_incref(&PyBaseObject_Type);
|
||||||
|
type->tp_basicsize = static_cast<ssize_t>(sizeof(instance));
|
||||||
|
type->tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HEAPTYPE;
|
||||||
|
|
||||||
|
type->tp_new = pybind11_object_new;
|
||||||
|
type->tp_init = pybind11_object_init;
|
||||||
|
type->tp_dealloc = pybind11_object_dealloc;
|
||||||
|
|
||||||
|
/* Support weak references (needed for the keep_alive feature) */
|
||||||
|
type->tp_weaklistoffset = offsetof(instance, weakrefs);
|
||||||
|
|
||||||
|
if (PyType_Ready(type) < 0)
|
||||||
|
pybind11_fail("PyType_Ready failed in make_object_base_type():" + error_string());
|
||||||
|
|
||||||
|
setattr((PyObject *) type, "__module__", str("pybind11_builtins"));
|
||||||
|
PYBIND11_SET_OLDPY_QUALNAME(type, name_obj);
|
||||||
|
|
||||||
|
assert(!PyType_HasFeature(type, Py_TPFLAGS_HAVE_GC));
|
||||||
|
return (PyObject *) heap_type;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// dynamic_attr: Support for `d = instance.__dict__`.
|
||||||
|
extern "C" inline PyObject *pybind11_get_dict(PyObject *self, void *) {
|
||||||
|
PyObject *&dict = *_PyObject_GetDictPtr(self);
|
||||||
|
if (!dict)
|
||||||
|
dict = PyDict_New();
|
||||||
|
Py_XINCREF(dict);
|
||||||
|
return dict;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// dynamic_attr: Support for `instance.__dict__ = dict()`.
|
||||||
|
extern "C" inline int pybind11_set_dict(PyObject *self, PyObject *new_dict, void *) {
|
||||||
|
if (!PyDict_Check(new_dict)) {
|
||||||
|
PyErr_Format(PyExc_TypeError, "__dict__ must be set to a dictionary, not a '%.200s'",
|
||||||
|
Py_TYPE(new_dict)->tp_name);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
PyObject *&dict = *_PyObject_GetDictPtr(self);
|
||||||
|
Py_INCREF(new_dict);
|
||||||
|
Py_CLEAR(dict);
|
||||||
|
dict = new_dict;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// dynamic_attr: Allow the garbage collector to traverse the internal instance `__dict__`.
|
||||||
|
extern "C" inline int pybind11_traverse(PyObject *self, visitproc visit, void *arg) {
|
||||||
|
PyObject *&dict = *_PyObject_GetDictPtr(self);
|
||||||
|
Py_VISIT(dict);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// dynamic_attr: Allow the GC to clear the dictionary.
|
||||||
|
extern "C" inline int pybind11_clear(PyObject *self) {
|
||||||
|
PyObject *&dict = *_PyObject_GetDictPtr(self);
|
||||||
|
Py_CLEAR(dict);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Give instances of this type a `__dict__` and opt into garbage collection.
|
||||||
|
inline void enable_dynamic_attributes(PyHeapTypeObject *heap_type) {
|
||||||
|
auto type = &heap_type->ht_type;
|
||||||
|
#if defined(PYPY_VERSION)
|
||||||
|
pybind11_fail(std::string(type->tp_name) + ": dynamic attributes are "
|
||||||
|
"currently not supported in "
|
||||||
|
"conjunction with PyPy!");
|
||||||
|
#endif
|
||||||
|
type->tp_flags |= Py_TPFLAGS_HAVE_GC;
|
||||||
|
type->tp_dictoffset = type->tp_basicsize; // place dict at the end
|
||||||
|
type->tp_basicsize += (ssize_t)sizeof(PyObject *); // and allocate enough space for it
|
||||||
|
type->tp_traverse = pybind11_traverse;
|
||||||
|
type->tp_clear = pybind11_clear;
|
||||||
|
|
||||||
|
static PyGetSetDef getset[] = {
|
||||||
|
{const_cast<char*>("__dict__"), pybind11_get_dict, pybind11_set_dict, nullptr, nullptr},
|
||||||
|
{nullptr, nullptr, nullptr, nullptr, nullptr}
|
||||||
|
};
|
||||||
|
type->tp_getset = getset;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// buffer_protocol: Fill in the view as specified by flags.
|
||||||
|
extern "C" inline int pybind11_getbuffer(PyObject *obj, Py_buffer *view, int flags) {
|
||||||
|
// Look for a `get_buffer` implementation in this type's info or any bases (following MRO).
|
||||||
|
type_info *tinfo = nullptr;
|
||||||
|
for (auto type : reinterpret_borrow<tuple>(Py_TYPE(obj)->tp_mro)) {
|
||||||
|
tinfo = get_type_info((PyTypeObject *) type.ptr());
|
||||||
|
if (tinfo && tinfo->get_buffer)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (view == nullptr || !tinfo || !tinfo->get_buffer) {
|
||||||
|
if (view)
|
||||||
|
view->obj = nullptr;
|
||||||
|
PyErr_SetString(PyExc_BufferError, "pybind11_getbuffer(): Internal error");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
std::memset(view, 0, sizeof(Py_buffer));
|
||||||
|
buffer_info *info = tinfo->get_buffer(obj, tinfo->get_buffer_data);
|
||||||
|
view->obj = obj;
|
||||||
|
view->ndim = 1;
|
||||||
|
view->internal = info;
|
||||||
|
view->buf = info->ptr;
|
||||||
|
view->itemsize = info->itemsize;
|
||||||
|
view->len = view->itemsize;
|
||||||
|
for (auto s : info->shape)
|
||||||
|
view->len *= s;
|
||||||
|
view->readonly = info->readonly;
|
||||||
|
if ((flags & PyBUF_WRITABLE) == PyBUF_WRITABLE && info->readonly) {
|
||||||
|
if (view)
|
||||||
|
view->obj = nullptr;
|
||||||
|
PyErr_SetString(PyExc_BufferError, "Writable buffer requested for readonly storage");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if ((flags & PyBUF_FORMAT) == PyBUF_FORMAT)
|
||||||
|
view->format = const_cast<char *>(info->format.c_str());
|
||||||
|
if ((flags & PyBUF_STRIDES) == PyBUF_STRIDES) {
|
||||||
|
view->ndim = (int) info->ndim;
|
||||||
|
view->strides = &info->strides[0];
|
||||||
|
view->shape = &info->shape[0];
|
||||||
|
}
|
||||||
|
Py_INCREF(view->obj);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// buffer_protocol: Release the resources of the buffer.
|
||||||
|
extern "C" inline void pybind11_releasebuffer(PyObject *, Py_buffer *view) {
|
||||||
|
delete (buffer_info *) view->internal;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Give this type a buffer interface.
|
||||||
|
inline void enable_buffer_protocol(PyHeapTypeObject *heap_type) {
|
||||||
|
heap_type->ht_type.tp_as_buffer = &heap_type->as_buffer;
|
||||||
|
#if PY_MAJOR_VERSION < 3
|
||||||
|
heap_type->ht_type.tp_flags |= Py_TPFLAGS_HAVE_NEWBUFFER;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
heap_type->as_buffer.bf_getbuffer = pybind11_getbuffer;
|
||||||
|
heap_type->as_buffer.bf_releasebuffer = pybind11_releasebuffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Create a brand new Python type according to the `type_record` specification.
|
||||||
|
Return value: New reference. */
|
||||||
|
inline PyObject* make_new_python_type(const type_record &rec) {
|
||||||
|
auto name = reinterpret_steal<object>(PYBIND11_FROM_STRING(rec.name));
|
||||||
|
|
||||||
|
auto qualname = name;
|
||||||
|
if (rec.scope && !PyModule_Check(rec.scope.ptr()) && hasattr(rec.scope, "__qualname__")) {
|
||||||
|
#if PY_MAJOR_VERSION >= 3
|
||||||
|
qualname = reinterpret_steal<object>(
|
||||||
|
PyUnicode_FromFormat("%U.%U", rec.scope.attr("__qualname__").ptr(), name.ptr()));
|
||||||
|
#else
|
||||||
|
qualname = str(rec.scope.attr("__qualname__").cast<std::string>() + "." + rec.name);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
object module;
|
||||||
|
if (rec.scope) {
|
||||||
|
if (hasattr(rec.scope, "__module__"))
|
||||||
|
module = rec.scope.attr("__module__");
|
||||||
|
else if (hasattr(rec.scope, "__name__"))
|
||||||
|
module = rec.scope.attr("__name__");
|
||||||
|
}
|
||||||
|
|
||||||
|
auto full_name = c_str(
|
||||||
|
#if !defined(PYPY_VERSION)
|
||||||
|
module ? str(module).cast<std::string>() + "." + rec.name :
|
||||||
|
#endif
|
||||||
|
rec.name);
|
||||||
|
|
||||||
|
char *tp_doc = nullptr;
|
||||||
|
if (rec.doc && options::show_user_defined_docstrings()) {
|
||||||
|
/* Allocate memory for docstring (using PyObject_MALLOC, since
|
||||||
|
Python will free this later on) */
|
||||||
|
size_t size = strlen(rec.doc) + 1;
|
||||||
|
tp_doc = (char *) PyObject_MALLOC(size);
|
||||||
|
memcpy((void *) tp_doc, rec.doc, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto &internals = get_internals();
|
||||||
|
auto bases = tuple(rec.bases);
|
||||||
|
auto base = (bases.size() == 0) ? internals.instance_base
|
||||||
|
: bases[0].ptr();
|
||||||
|
|
||||||
|
/* Danger zone: from now (and until PyType_Ready), make sure to
|
||||||
|
issue no Python C API calls which could potentially invoke the
|
||||||
|
garbage collector (the GC will call type_traverse(), which will in
|
||||||
|
turn find the newly constructed type in an invalid state) */
|
||||||
|
auto metaclass = rec.metaclass.ptr() ? (PyTypeObject *) rec.metaclass.ptr()
|
||||||
|
: internals.default_metaclass;
|
||||||
|
|
||||||
|
auto heap_type = (PyHeapTypeObject *) metaclass->tp_alloc(metaclass, 0);
|
||||||
|
if (!heap_type)
|
||||||
|
pybind11_fail(std::string(rec.name) + ": Unable to create type object!");
|
||||||
|
|
||||||
|
heap_type->ht_name = name.release().ptr();
|
||||||
|
#ifdef PYBIND11_BUILTIN_QUALNAME
|
||||||
|
heap_type->ht_qualname = qualname.inc_ref().ptr();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
auto type = &heap_type->ht_type;
|
||||||
|
type->tp_name = full_name;
|
||||||
|
type->tp_doc = tp_doc;
|
||||||
|
type->tp_base = type_incref((PyTypeObject *)base);
|
||||||
|
type->tp_basicsize = static_cast<ssize_t>(sizeof(instance));
|
||||||
|
if (bases.size() > 0)
|
||||||
|
type->tp_bases = bases.release().ptr();
|
||||||
|
|
||||||
|
/* Don't inherit base __init__ */
|
||||||
|
type->tp_init = pybind11_object_init;
|
||||||
|
|
||||||
|
/* Supported protocols */
|
||||||
|
type->tp_as_number = &heap_type->as_number;
|
||||||
|
type->tp_as_sequence = &heap_type->as_sequence;
|
||||||
|
type->tp_as_mapping = &heap_type->as_mapping;
|
||||||
|
#if PY_VERSION_HEX >= 0x03050000
|
||||||
|
type->tp_as_async = &heap_type->as_async;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Flags */
|
||||||
|
type->tp_flags |= Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HEAPTYPE;
|
||||||
|
#if PY_MAJOR_VERSION < 3
|
||||||
|
type->tp_flags |= Py_TPFLAGS_CHECKTYPES;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (rec.dynamic_attr)
|
||||||
|
enable_dynamic_attributes(heap_type);
|
||||||
|
|
||||||
|
if (rec.buffer_protocol)
|
||||||
|
enable_buffer_protocol(heap_type);
|
||||||
|
|
||||||
|
if (PyType_Ready(type) < 0)
|
||||||
|
pybind11_fail(std::string(rec.name) + ": PyType_Ready failed (" + error_string() + ")!");
|
||||||
|
|
||||||
|
assert(rec.dynamic_attr ? PyType_HasFeature(type, Py_TPFLAGS_HAVE_GC)
|
||||||
|
: !PyType_HasFeature(type, Py_TPFLAGS_HAVE_GC));
|
||||||
|
|
||||||
|
/* Register type with the parent scope */
|
||||||
|
if (rec.scope)
|
||||||
|
setattr(rec.scope, rec.name, (PyObject *) type);
|
||||||
|
else
|
||||||
|
Py_INCREF(type); // Keep it alive forever (reference leak)
|
||||||
|
|
||||||
|
if (module) // Needed by pydoc
|
||||||
|
setattr((PyObject *) type, "__module__", module);
|
||||||
|
|
||||||
|
PYBIND11_SET_OLDPY_QUALNAME(type, qualname);
|
||||||
|
|
||||||
|
return (PyObject *) type;
|
||||||
|
}
|
||||||
|
|
||||||
|
NAMESPACE_END(detail)
|
||||||
|
NAMESPACE_END(PYBIND11_NAMESPACE)
|
820
3rdparty/pybind11/include/pybind11/detail/common.h
vendored
Normal file
820
3rdparty/pybind11/include/pybind11/detail/common.h
vendored
Normal file
@ -0,0 +1,820 @@
|
|||||||
|
/*
|
||||||
|
pybind11/detail/common.h -- Basic macros
|
||||||
|
|
||||||
|
Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch>
|
||||||
|
|
||||||
|
All rights reserved. Use of this source code is governed by a
|
||||||
|
BSD-style license that can be found in the LICENSE file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#if !defined(NAMESPACE_BEGIN)
|
||||||
|
# define NAMESPACE_BEGIN(name) namespace name {
|
||||||
|
#endif
|
||||||
|
#if !defined(NAMESPACE_END)
|
||||||
|
# define NAMESPACE_END(name) }
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Robust support for some features and loading modules compiled against different pybind versions
|
||||||
|
// requires forcing hidden visibility on pybind code, so we enforce this by setting the attribute on
|
||||||
|
// the main `pybind11` namespace.
|
||||||
|
#if !defined(PYBIND11_NAMESPACE)
|
||||||
|
# ifdef __GNUG__
|
||||||
|
# define PYBIND11_NAMESPACE pybind11 __attribute__((visibility("hidden")))
|
||||||
|
# else
|
||||||
|
# define PYBIND11_NAMESPACE pybind11
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if !(defined(_MSC_VER) && __cplusplus == 199711L) && !defined(__INTEL_COMPILER)
|
||||||
|
# if __cplusplus >= 201402L
|
||||||
|
# define PYBIND11_CPP14
|
||||||
|
# if __cplusplus >= 201703L
|
||||||
|
# define PYBIND11_CPP17
|
||||||
|
# endif
|
||||||
|
# endif
|
||||||
|
#elif defined(_MSC_VER) && __cplusplus == 199711L
|
||||||
|
// MSVC sets _MSVC_LANG rather than __cplusplus (supposedly until the standard is fully implemented)
|
||||||
|
// Unless you use the /Zc:__cplusplus flag on Visual Studio 2017 15.7 Preview 3 or newer
|
||||||
|
# if _MSVC_LANG >= 201402L
|
||||||
|
# define PYBIND11_CPP14
|
||||||
|
# if _MSVC_LANG > 201402L && _MSC_VER >= 1910
|
||||||
|
# define PYBIND11_CPP17
|
||||||
|
# endif
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Compiler version assertions
|
||||||
|
#if defined(__INTEL_COMPILER)
|
||||||
|
# if __INTEL_COMPILER < 1700
|
||||||
|
# error pybind11 requires Intel C++ compiler v17 or newer
|
||||||
|
# endif
|
||||||
|
#elif defined(__clang__) && !defined(__apple_build_version__)
|
||||||
|
# if __clang_major__ < 3 || (__clang_major__ == 3 && __clang_minor__ < 3)
|
||||||
|
# error pybind11 requires clang 3.3 or newer
|
||||||
|
# endif
|
||||||
|
#elif defined(__clang__)
|
||||||
|
// Apple changes clang version macros to its Xcode version; the first Xcode release based on
|
||||||
|
// (upstream) clang 3.3 was Xcode 5:
|
||||||
|
# if __clang_major__ < 5
|
||||||
|
# error pybind11 requires Xcode/clang 5.0 or newer
|
||||||
|
# endif
|
||||||
|
#elif defined(__GNUG__)
|
||||||
|
# if __GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 8)
|
||||||
|
# error pybind11 requires gcc 4.8 or newer
|
||||||
|
# endif
|
||||||
|
#elif defined(_MSC_VER)
|
||||||
|
// Pybind hits various compiler bugs in 2015u2 and earlier, and also makes use of some stl features
|
||||||
|
// (e.g. std::negation) added in 2015u3:
|
||||||
|
# if _MSC_FULL_VER < 190024210
|
||||||
|
# error pybind11 requires MSVC 2015 update 3 or newer
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if !defined(PYBIND11_EXPORT)
|
||||||
|
# if defined(WIN32) || defined(_WIN32)
|
||||||
|
# define PYBIND11_EXPORT __declspec(dllexport)
|
||||||
|
# else
|
||||||
|
# define PYBIND11_EXPORT __attribute__ ((visibility("default")))
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(_MSC_VER)
|
||||||
|
# define PYBIND11_NOINLINE __declspec(noinline)
|
||||||
|
#else
|
||||||
|
# define PYBIND11_NOINLINE __attribute__ ((noinline))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(PYBIND11_CPP14)
|
||||||
|
# define PYBIND11_DEPRECATED(reason) [[deprecated(reason)]]
|
||||||
|
#else
|
||||||
|
# define PYBIND11_DEPRECATED(reason) __attribute__((deprecated(reason)))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define PYBIND11_VERSION_MAJOR 2
|
||||||
|
#define PYBIND11_VERSION_MINOR 5
|
||||||
|
#define PYBIND11_VERSION_PATCH 0
|
||||||
|
|
||||||
|
/// Include Python header, disable linking to pythonX_d.lib on Windows in debug mode
|
||||||
|
#if defined(_MSC_VER)
|
||||||
|
# if (PY_MAJOR_VERSION == 3 && PY_MINOR_VERSION < 4)
|
||||||
|
# define HAVE_ROUND 1
|
||||||
|
# endif
|
||||||
|
# pragma warning(push)
|
||||||
|
# pragma warning(disable: 4510 4610 4512 4005)
|
||||||
|
# if defined(_DEBUG) && !defined(Py_DEBUG)
|
||||||
|
# define PYBIND11_DEBUG_MARKER
|
||||||
|
# undef _DEBUG
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <Python.h>
|
||||||
|
#include <frameobject.h>
|
||||||
|
#include <pythread.h>
|
||||||
|
|
||||||
|
/* Python #defines overrides on all sorts of core functions, which
|
||||||
|
tends to weak havok in C++ codebases that expect these to work
|
||||||
|
like regular functions (potentially with several overloads) */
|
||||||
|
#if defined(isalnum)
|
||||||
|
# undef isalnum
|
||||||
|
# undef isalpha
|
||||||
|
# undef islower
|
||||||
|
# undef isspace
|
||||||
|
# undef isupper
|
||||||
|
# undef tolower
|
||||||
|
# undef toupper
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(copysign)
|
||||||
|
# undef copysign
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(_MSC_VER)
|
||||||
|
# if defined(PYBIND11_DEBUG_MARKER)
|
||||||
|
# define _DEBUG
|
||||||
|
# undef PYBIND11_DEBUG_MARKER
|
||||||
|
# endif
|
||||||
|
# pragma warning(pop)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <cstddef>
|
||||||
|
#include <cstring>
|
||||||
|
#include <forward_list>
|
||||||
|
#include <vector>
|
||||||
|
#include <string>
|
||||||
|
#include <stdexcept>
|
||||||
|
#include <unordered_set>
|
||||||
|
#include <unordered_map>
|
||||||
|
#include <memory>
|
||||||
|
#include <typeindex>
|
||||||
|
#include <type_traits>
|
||||||
|
|
||||||
|
#if PY_MAJOR_VERSION >= 3 /// Compatibility macros for various Python versions
|
||||||
|
#define PYBIND11_INSTANCE_METHOD_NEW(ptr, class_) PyInstanceMethod_New(ptr)
|
||||||
|
#define PYBIND11_INSTANCE_METHOD_CHECK PyInstanceMethod_Check
|
||||||
|
#define PYBIND11_INSTANCE_METHOD_GET_FUNCTION PyInstanceMethod_GET_FUNCTION
|
||||||
|
#define PYBIND11_BYTES_CHECK PyBytes_Check
|
||||||
|
#define PYBIND11_BYTES_FROM_STRING PyBytes_FromString
|
||||||
|
#define PYBIND11_BYTES_FROM_STRING_AND_SIZE PyBytes_FromStringAndSize
|
||||||
|
#define PYBIND11_BYTES_AS_STRING_AND_SIZE PyBytes_AsStringAndSize
|
||||||
|
#define PYBIND11_BYTES_AS_STRING PyBytes_AsString
|
||||||
|
#define PYBIND11_BYTES_SIZE PyBytes_Size
|
||||||
|
#define PYBIND11_LONG_CHECK(o) PyLong_Check(o)
|
||||||
|
#define PYBIND11_LONG_AS_LONGLONG(o) PyLong_AsLongLong(o)
|
||||||
|
#define PYBIND11_LONG_FROM_SIGNED(o) PyLong_FromSsize_t((ssize_t) o)
|
||||||
|
#define PYBIND11_LONG_FROM_UNSIGNED(o) PyLong_FromSize_t((size_t) o)
|
||||||
|
#define PYBIND11_BYTES_NAME "bytes"
|
||||||
|
#define PYBIND11_STRING_NAME "str"
|
||||||
|
#define PYBIND11_SLICE_OBJECT PyObject
|
||||||
|
#define PYBIND11_FROM_STRING PyUnicode_FromString
|
||||||
|
#define PYBIND11_STR_TYPE ::pybind11::str
|
||||||
|
#define PYBIND11_BOOL_ATTR "__bool__"
|
||||||
|
#define PYBIND11_NB_BOOL(ptr) ((ptr)->nb_bool)
|
||||||
|
// Providing a separate declaration to make Clang's -Wmissing-prototypes happy
|
||||||
|
#define PYBIND11_PLUGIN_IMPL(name) \
|
||||||
|
extern "C" PYBIND11_EXPORT PyObject *PyInit_##name(); \
|
||||||
|
extern "C" PYBIND11_EXPORT PyObject *PyInit_##name()
|
||||||
|
|
||||||
|
#else
|
||||||
|
#define PYBIND11_INSTANCE_METHOD_NEW(ptr, class_) PyMethod_New(ptr, nullptr, class_)
|
||||||
|
#define PYBIND11_INSTANCE_METHOD_CHECK PyMethod_Check
|
||||||
|
#define PYBIND11_INSTANCE_METHOD_GET_FUNCTION PyMethod_GET_FUNCTION
|
||||||
|
#define PYBIND11_BYTES_CHECK PyString_Check
|
||||||
|
#define PYBIND11_BYTES_FROM_STRING PyString_FromString
|
||||||
|
#define PYBIND11_BYTES_FROM_STRING_AND_SIZE PyString_FromStringAndSize
|
||||||
|
#define PYBIND11_BYTES_AS_STRING_AND_SIZE PyString_AsStringAndSize
|
||||||
|
#define PYBIND11_BYTES_AS_STRING PyString_AsString
|
||||||
|
#define PYBIND11_BYTES_SIZE PyString_Size
|
||||||
|
#define PYBIND11_LONG_CHECK(o) (PyInt_Check(o) || PyLong_Check(o))
|
||||||
|
#define PYBIND11_LONG_AS_LONGLONG(o) (PyInt_Check(o) ? (long long) PyLong_AsLong(o) : PyLong_AsLongLong(o))
|
||||||
|
#define PYBIND11_LONG_FROM_SIGNED(o) PyInt_FromSsize_t((ssize_t) o) // Returns long if needed.
|
||||||
|
#define PYBIND11_LONG_FROM_UNSIGNED(o) PyInt_FromSize_t((size_t) o) // Returns long if needed.
|
||||||
|
#define PYBIND11_BYTES_NAME "str"
|
||||||
|
#define PYBIND11_STRING_NAME "unicode"
|
||||||
|
#define PYBIND11_SLICE_OBJECT PySliceObject
|
||||||
|
#define PYBIND11_FROM_STRING PyString_FromString
|
||||||
|
#define PYBIND11_STR_TYPE ::pybind11::bytes
|
||||||
|
#define PYBIND11_BOOL_ATTR "__nonzero__"
|
||||||
|
#define PYBIND11_NB_BOOL(ptr) ((ptr)->nb_nonzero)
|
||||||
|
// Providing a separate PyInit decl to make Clang's -Wmissing-prototypes happy
|
||||||
|
#define PYBIND11_PLUGIN_IMPL(name) \
|
||||||
|
static PyObject *pybind11_init_wrapper(); \
|
||||||
|
extern "C" PYBIND11_EXPORT void init##name(); \
|
||||||
|
extern "C" PYBIND11_EXPORT void init##name() { \
|
||||||
|
(void)pybind11_init_wrapper(); \
|
||||||
|
} \
|
||||||
|
PyObject *pybind11_init_wrapper()
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if PY_VERSION_HEX >= 0x03050000 && PY_VERSION_HEX < 0x03050200
|
||||||
|
extern "C" {
|
||||||
|
struct _Py_atomic_address { void *value; };
|
||||||
|
PyAPI_DATA(_Py_atomic_address) _PyThreadState_Current;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define PYBIND11_TRY_NEXT_OVERLOAD ((PyObject *) 1) // special failure return code
|
||||||
|
#define PYBIND11_STRINGIFY(x) #x
|
||||||
|
#define PYBIND11_TOSTRING(x) PYBIND11_STRINGIFY(x)
|
||||||
|
#define PYBIND11_CONCAT(first, second) first##second
|
||||||
|
#define PYBIND11_ENSURE_INTERNALS_READY \
|
||||||
|
pybind11::detail::get_internals();
|
||||||
|
|
||||||
|
#define PYBIND11_CHECK_PYTHON_VERSION \
|
||||||
|
{ \
|
||||||
|
const char *compiled_ver = PYBIND11_TOSTRING(PY_MAJOR_VERSION) \
|
||||||
|
"." PYBIND11_TOSTRING(PY_MINOR_VERSION); \
|
||||||
|
const char *runtime_ver = Py_GetVersion(); \
|
||||||
|
size_t len = std::strlen(compiled_ver); \
|
||||||
|
if (std::strncmp(runtime_ver, compiled_ver, len) != 0 \
|
||||||
|
|| (runtime_ver[len] >= '0' && runtime_ver[len] <= '9')) { \
|
||||||
|
PyErr_Format(PyExc_ImportError, \
|
||||||
|
"Python version mismatch: module was compiled for Python %s, " \
|
||||||
|
"but the interpreter version is incompatible: %s.", \
|
||||||
|
compiled_ver, runtime_ver); \
|
||||||
|
return nullptr; \
|
||||||
|
} \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define PYBIND11_CATCH_INIT_EXCEPTIONS \
|
||||||
|
catch (pybind11::error_already_set &e) { \
|
||||||
|
PyErr_SetString(PyExc_ImportError, e.what()); \
|
||||||
|
return nullptr; \
|
||||||
|
} catch (const std::exception &e) { \
|
||||||
|
PyErr_SetString(PyExc_ImportError, e.what()); \
|
||||||
|
return nullptr; \
|
||||||
|
} \
|
||||||
|
|
||||||
|
/** \rst
|
||||||
|
***Deprecated in favor of PYBIND11_MODULE***
|
||||||
|
|
||||||
|
This macro creates the entry point that will be invoked when the Python interpreter
|
||||||
|
imports a plugin library. Please create a `module` in the function body and return
|
||||||
|
the pointer to its underlying Python object at the end.
|
||||||
|
|
||||||
|
.. code-block:: cpp
|
||||||
|
|
||||||
|
PYBIND11_PLUGIN(example) {
|
||||||
|
pybind11::module m("example", "pybind11 example plugin");
|
||||||
|
/// Set up bindings here
|
||||||
|
return m.ptr();
|
||||||
|
}
|
||||||
|
\endrst */
|
||||||
|
#define PYBIND11_PLUGIN(name) \
|
||||||
|
PYBIND11_DEPRECATED("PYBIND11_PLUGIN is deprecated, use PYBIND11_MODULE") \
|
||||||
|
static PyObject *pybind11_init(); \
|
||||||
|
PYBIND11_PLUGIN_IMPL(name) { \
|
||||||
|
PYBIND11_CHECK_PYTHON_VERSION \
|
||||||
|
PYBIND11_ENSURE_INTERNALS_READY \
|
||||||
|
try { \
|
||||||
|
return pybind11_init(); \
|
||||||
|
} PYBIND11_CATCH_INIT_EXCEPTIONS \
|
||||||
|
} \
|
||||||
|
PyObject *pybind11_init()
|
||||||
|
|
||||||
|
/** \rst
|
||||||
|
This macro creates the entry point that will be invoked when the Python interpreter
|
||||||
|
imports an extension module. The module name is given as the fist argument and it
|
||||||
|
should not be in quotes. The second macro argument defines a variable of type
|
||||||
|
`py::module` which can be used to initialize the module.
|
||||||
|
|
||||||
|
.. code-block:: cpp
|
||||||
|
|
||||||
|
PYBIND11_MODULE(example, m) {
|
||||||
|
m.doc() = "pybind11 example module";
|
||||||
|
|
||||||
|
// Add bindings here
|
||||||
|
m.def("foo", []() {
|
||||||
|
return "Hello, World!";
|
||||||
|
});
|
||||||
|
}
|
||||||
|
\endrst */
|
||||||
|
#define PYBIND11_MODULE(name, variable) \
|
||||||
|
static void PYBIND11_CONCAT(pybind11_init_, name)(pybind11::module &); \
|
||||||
|
PYBIND11_PLUGIN_IMPL(name) { \
|
||||||
|
PYBIND11_CHECK_PYTHON_VERSION \
|
||||||
|
PYBIND11_ENSURE_INTERNALS_READY \
|
||||||
|
auto m = pybind11::module(PYBIND11_TOSTRING(name)); \
|
||||||
|
try { \
|
||||||
|
PYBIND11_CONCAT(pybind11_init_, name)(m); \
|
||||||
|
return m.ptr(); \
|
||||||
|
} PYBIND11_CATCH_INIT_EXCEPTIONS \
|
||||||
|
} \
|
||||||
|
void PYBIND11_CONCAT(pybind11_init_, name)(pybind11::module &variable)
|
||||||
|
|
||||||
|
|
||||||
|
NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
|
||||||
|
|
||||||
|
using ssize_t = Py_ssize_t;
|
||||||
|
using size_t = std::size_t;
|
||||||
|
|
||||||
|
/// Approach used to cast a previously unknown C++ instance into a Python object
|
||||||
|
enum class return_value_policy : uint8_t {
|
||||||
|
/** This is the default return value policy, which falls back to the policy
|
||||||
|
return_value_policy::take_ownership when the return value is a pointer.
|
||||||
|
Otherwise, it uses return_value::move or return_value::copy for rvalue
|
||||||
|
and lvalue references, respectively. See below for a description of what
|
||||||
|
all of these different policies do. */
|
||||||
|
automatic = 0,
|
||||||
|
|
||||||
|
/** As above, but use policy return_value_policy::reference when the return
|
||||||
|
value is a pointer. This is the default conversion policy for function
|
||||||
|
arguments when calling Python functions manually from C++ code (i.e. via
|
||||||
|
handle::operator()). You probably won't need to use this. */
|
||||||
|
automatic_reference,
|
||||||
|
|
||||||
|
/** Reference an existing object (i.e. do not create a new copy) and take
|
||||||
|
ownership. Python will call the destructor and delete operator when the
|
||||||
|
object’s reference count reaches zero. Undefined behavior ensues when
|
||||||
|
the C++ side does the same.. */
|
||||||
|
take_ownership,
|
||||||
|
|
||||||
|
/** Create a new copy of the returned object, which will be owned by
|
||||||
|
Python. This policy is comparably safe because the lifetimes of the two
|
||||||
|
instances are decoupled. */
|
||||||
|
copy,
|
||||||
|
|
||||||
|
/** Use std::move to move the return value contents into a new instance
|
||||||
|
that will be owned by Python. This policy is comparably safe because the
|
||||||
|
lifetimes of the two instances (move source and destination) are
|
||||||
|
decoupled. */
|
||||||
|
move,
|
||||||
|
|
||||||
|
/** Reference an existing object, but do not take ownership. The C++ side
|
||||||
|
is responsible for managing the object’s lifetime and deallocating it
|
||||||
|
when it is no longer used. Warning: undefined behavior will ensue when
|
||||||
|
the C++ side deletes an object that is still referenced and used by
|
||||||
|
Python. */
|
||||||
|
reference,
|
||||||
|
|
||||||
|
/** This policy only applies to methods and properties. It references the
|
||||||
|
object without taking ownership similar to the above
|
||||||
|
return_value_policy::reference policy. In contrast to that policy, the
|
||||||
|
function or property’s implicit this argument (called the parent) is
|
||||||
|
considered to be the the owner of the return value (the child).
|
||||||
|
pybind11 then couples the lifetime of the parent to the child via a
|
||||||
|
reference relationship that ensures that the parent cannot be garbage
|
||||||
|
collected while Python is still using the child. More advanced
|
||||||
|
variations of this scheme are also possible using combinations of
|
||||||
|
return_value_policy::reference and the keep_alive call policy */
|
||||||
|
reference_internal
|
||||||
|
};
|
||||||
|
|
||||||
|
NAMESPACE_BEGIN(detail)
|
||||||
|
|
||||||
|
inline static constexpr int log2(size_t n, int k = 0) { return (n <= 1) ? k : log2(n >> 1, k + 1); }
|
||||||
|
|
||||||
|
// Returns the size as a multiple of sizeof(void *), rounded up.
|
||||||
|
inline static constexpr size_t size_in_ptrs(size_t s) { return 1 + ((s - 1) >> log2(sizeof(void *))); }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The space to allocate for simple layout instance holders (see below) in multiple of the size of
|
||||||
|
* a pointer (e.g. 2 means 16 bytes on 64-bit architectures). The default is the minimum required
|
||||||
|
* to holder either a std::unique_ptr or std::shared_ptr (which is almost always
|
||||||
|
* sizeof(std::shared_ptr<T>)).
|
||||||
|
*/
|
||||||
|
constexpr size_t instance_simple_holder_in_ptrs() {
|
||||||
|
static_assert(sizeof(std::shared_ptr<int>) >= sizeof(std::unique_ptr<int>),
|
||||||
|
"pybind assumes std::shared_ptrs are at least as big as std::unique_ptrs");
|
||||||
|
return size_in_ptrs(sizeof(std::shared_ptr<int>));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Forward declarations
|
||||||
|
struct type_info;
|
||||||
|
struct value_and_holder;
|
||||||
|
|
||||||
|
struct nonsimple_values_and_holders {
|
||||||
|
void **values_and_holders;
|
||||||
|
uint8_t *status;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// The 'instance' type which needs to be standard layout (need to be able to use 'offsetof')
|
||||||
|
struct instance {
|
||||||
|
PyObject_HEAD
|
||||||
|
/// Storage for pointers and holder; see simple_layout, below, for a description
|
||||||
|
union {
|
||||||
|
void *simple_value_holder[1 + instance_simple_holder_in_ptrs()];
|
||||||
|
nonsimple_values_and_holders nonsimple;
|
||||||
|
};
|
||||||
|
/// Weak references
|
||||||
|
PyObject *weakrefs;
|
||||||
|
/// If true, the pointer is owned which means we're free to manage it with a holder.
|
||||||
|
bool owned : 1;
|
||||||
|
/**
|
||||||
|
* An instance has two possible value/holder layouts.
|
||||||
|
*
|
||||||
|
* Simple layout (when this flag is true), means the `simple_value_holder` is set with a pointer
|
||||||
|
* and the holder object governing that pointer, i.e. [val1*][holder]. This layout is applied
|
||||||
|
* whenever there is no python-side multiple inheritance of bound C++ types *and* the type's
|
||||||
|
* holder will fit in the default space (which is large enough to hold either a std::unique_ptr
|
||||||
|
* or std::shared_ptr).
|
||||||
|
*
|
||||||
|
* Non-simple layout applies when using custom holders that require more space than `shared_ptr`
|
||||||
|
* (which is typically the size of two pointers), or when multiple inheritance is used on the
|
||||||
|
* python side. Non-simple layout allocates the required amount of memory to have multiple
|
||||||
|
* bound C++ classes as parents. Under this layout, `nonsimple.values_and_holders` is set to a
|
||||||
|
* pointer to allocated space of the required space to hold a sequence of value pointers and
|
||||||
|
* holders followed `status`, a set of bit flags (1 byte each), i.e.
|
||||||
|
* [val1*][holder1][val2*][holder2]...[bb...] where each [block] is rounded up to a multiple of
|
||||||
|
* `sizeof(void *)`. `nonsimple.status` is, for convenience, a pointer to the
|
||||||
|
* beginning of the [bb...] block (but not independently allocated).
|
||||||
|
*
|
||||||
|
* Status bits indicate whether the associated holder is constructed (&
|
||||||
|
* status_holder_constructed) and whether the value pointer is registered (&
|
||||||
|
* status_instance_registered) in `registered_instances`.
|
||||||
|
*/
|
||||||
|
bool simple_layout : 1;
|
||||||
|
/// For simple layout, tracks whether the holder has been constructed
|
||||||
|
bool simple_holder_constructed : 1;
|
||||||
|
/// For simple layout, tracks whether the instance is registered in `registered_instances`
|
||||||
|
bool simple_instance_registered : 1;
|
||||||
|
/// If true, get_internals().patients has an entry for this object
|
||||||
|
bool has_patients : 1;
|
||||||
|
|
||||||
|
/// Initializes all of the above type/values/holders data (but not the instance values themselves)
|
||||||
|
void allocate_layout();
|
||||||
|
|
||||||
|
/// Destroys/deallocates all of the above
|
||||||
|
void deallocate_layout();
|
||||||
|
|
||||||
|
/// Returns the value_and_holder wrapper for the given type (or the first, if `find_type`
|
||||||
|
/// omitted). Returns a default-constructed (with `.inst = nullptr`) object on failure if
|
||||||
|
/// `throw_if_missing` is false.
|
||||||
|
value_and_holder get_value_and_holder(const type_info *find_type = nullptr, bool throw_if_missing = true);
|
||||||
|
|
||||||
|
/// Bit values for the non-simple status flags
|
||||||
|
static constexpr uint8_t status_holder_constructed = 1;
|
||||||
|
static constexpr uint8_t status_instance_registered = 2;
|
||||||
|
};
|
||||||
|
|
||||||
|
static_assert(std::is_standard_layout<instance>::value, "Internal error: `pybind11::detail::instance` is not standard layout!");
|
||||||
|
|
||||||
|
/// from __cpp_future__ import (convenient aliases from C++14/17)
|
||||||
|
#if defined(PYBIND11_CPP14) && (!defined(_MSC_VER) || _MSC_VER >= 1910)
|
||||||
|
using std::enable_if_t;
|
||||||
|
using std::conditional_t;
|
||||||
|
using std::remove_cv_t;
|
||||||
|
using std::remove_reference_t;
|
||||||
|
#else
|
||||||
|
template <bool B, typename T = void> using enable_if_t = typename std::enable_if<B, T>::type;
|
||||||
|
template <bool B, typename T, typename F> using conditional_t = typename std::conditional<B, T, F>::type;
|
||||||
|
template <typename T> using remove_cv_t = typename std::remove_cv<T>::type;
|
||||||
|
template <typename T> using remove_reference_t = typename std::remove_reference<T>::type;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/// Index sequences
|
||||||
|
#if defined(PYBIND11_CPP14)
|
||||||
|
using std::index_sequence;
|
||||||
|
using std::make_index_sequence;
|
||||||
|
#else
|
||||||
|
template<size_t ...> struct index_sequence { };
|
||||||
|
template<size_t N, size_t ...S> struct make_index_sequence_impl : make_index_sequence_impl <N - 1, N - 1, S...> { };
|
||||||
|
template<size_t ...S> struct make_index_sequence_impl <0, S...> { typedef index_sequence<S...> type; };
|
||||||
|
template<size_t N> using make_index_sequence = typename make_index_sequence_impl<N>::type;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/// Make an index sequence of the indices of true arguments
|
||||||
|
template <typename ISeq, size_t, bool...> struct select_indices_impl { using type = ISeq; };
|
||||||
|
template <size_t... IPrev, size_t I, bool B, bool... Bs> struct select_indices_impl<index_sequence<IPrev...>, I, B, Bs...>
|
||||||
|
: select_indices_impl<conditional_t<B, index_sequence<IPrev..., I>, index_sequence<IPrev...>>, I + 1, Bs...> {};
|
||||||
|
template <bool... Bs> using select_indices = typename select_indices_impl<index_sequence<>, 0, Bs...>::type;
|
||||||
|
|
||||||
|
/// Backports of std::bool_constant and std::negation to accommodate older compilers
|
||||||
|
template <bool B> using bool_constant = std::integral_constant<bool, B>;
|
||||||
|
template <typename T> struct negation : bool_constant<!T::value> { };
|
||||||
|
|
||||||
|
template <typename...> struct void_t_impl { using type = void; };
|
||||||
|
template <typename... Ts> using void_t = typename void_t_impl<Ts...>::type;
|
||||||
|
|
||||||
|
/// Compile-time all/any/none of that check the boolean value of all template types
|
||||||
|
#if defined(__cpp_fold_expressions) && !(defined(_MSC_VER) && (_MSC_VER < 1916))
|
||||||
|
template <class... Ts> using all_of = bool_constant<(Ts::value && ...)>;
|
||||||
|
template <class... Ts> using any_of = bool_constant<(Ts::value || ...)>;
|
||||||
|
#elif !defined(_MSC_VER)
|
||||||
|
template <bool...> struct bools {};
|
||||||
|
template <class... Ts> using all_of = std::is_same<
|
||||||
|
bools<Ts::value..., true>,
|
||||||
|
bools<true, Ts::value...>>;
|
||||||
|
template <class... Ts> using any_of = negation<all_of<negation<Ts>...>>;
|
||||||
|
#else
|
||||||
|
// MSVC has trouble with the above, but supports std::conjunction, which we can use instead (albeit
|
||||||
|
// at a slight loss of compilation efficiency).
|
||||||
|
template <class... Ts> using all_of = std::conjunction<Ts...>;
|
||||||
|
template <class... Ts> using any_of = std::disjunction<Ts...>;
|
||||||
|
#endif
|
||||||
|
template <class... Ts> using none_of = negation<any_of<Ts...>>;
|
||||||
|
|
||||||
|
template <class T, template<class> class... Predicates> using satisfies_all_of = all_of<Predicates<T>...>;
|
||||||
|
template <class T, template<class> class... Predicates> using satisfies_any_of = any_of<Predicates<T>...>;
|
||||||
|
template <class T, template<class> class... Predicates> using satisfies_none_of = none_of<Predicates<T>...>;
|
||||||
|
|
||||||
|
/// Strip the class from a method type
|
||||||
|
template <typename T> struct remove_class { };
|
||||||
|
template <typename C, typename R, typename... A> struct remove_class<R (C::*)(A...)> { typedef R type(A...); };
|
||||||
|
template <typename C, typename R, typename... A> struct remove_class<R (C::*)(A...) const> { typedef R type(A...); };
|
||||||
|
|
||||||
|
/// Helper template to strip away type modifiers
|
||||||
|
template <typename T> struct intrinsic_type { typedef T type; };
|
||||||
|
template <typename T> struct intrinsic_type<const T> { typedef typename intrinsic_type<T>::type type; };
|
||||||
|
template <typename T> struct intrinsic_type<T*> { typedef typename intrinsic_type<T>::type type; };
|
||||||
|
template <typename T> struct intrinsic_type<T&> { typedef typename intrinsic_type<T>::type type; };
|
||||||
|
template <typename T> struct intrinsic_type<T&&> { typedef typename intrinsic_type<T>::type type; };
|
||||||
|
template <typename T, size_t N> struct intrinsic_type<const T[N]> { typedef typename intrinsic_type<T>::type type; };
|
||||||
|
template <typename T, size_t N> struct intrinsic_type<T[N]> { typedef typename intrinsic_type<T>::type type; };
|
||||||
|
template <typename T> using intrinsic_t = typename intrinsic_type<T>::type;
|
||||||
|
|
||||||
|
/// Helper type to replace 'void' in some expressions
|
||||||
|
struct void_type { };
|
||||||
|
|
||||||
|
/// Helper template which holds a list of types
|
||||||
|
template <typename...> struct type_list { };
|
||||||
|
|
||||||
|
/// Compile-time integer sum
|
||||||
|
#ifdef __cpp_fold_expressions
|
||||||
|
template <typename... Ts> constexpr size_t constexpr_sum(Ts... ns) { return (0 + ... + size_t{ns}); }
|
||||||
|
#else
|
||||||
|
constexpr size_t constexpr_sum() { return 0; }
|
||||||
|
template <typename T, typename... Ts>
|
||||||
|
constexpr size_t constexpr_sum(T n, Ts... ns) { return size_t{n} + constexpr_sum(ns...); }
|
||||||
|
#endif
|
||||||
|
|
||||||
|
NAMESPACE_BEGIN(constexpr_impl)
|
||||||
|
/// Implementation details for constexpr functions
|
||||||
|
constexpr int first(int i) { return i; }
|
||||||
|
template <typename T, typename... Ts>
|
||||||
|
constexpr int first(int i, T v, Ts... vs) { return v ? i : first(i + 1, vs...); }
|
||||||
|
|
||||||
|
constexpr int last(int /*i*/, int result) { return result; }
|
||||||
|
template <typename T, typename... Ts>
|
||||||
|
constexpr int last(int i, int result, T v, Ts... vs) { return last(i + 1, v ? i : result, vs...); }
|
||||||
|
NAMESPACE_END(constexpr_impl)
|
||||||
|
|
||||||
|
/// Return the index of the first type in Ts which satisfies Predicate<T>. Returns sizeof...(Ts) if
|
||||||
|
/// none match.
|
||||||
|
template <template<typename> class Predicate, typename... Ts>
|
||||||
|
constexpr int constexpr_first() { return constexpr_impl::first(0, Predicate<Ts>::value...); }
|
||||||
|
|
||||||
|
/// Return the index of the last type in Ts which satisfies Predicate<T>, or -1 if none match.
|
||||||
|
template <template<typename> class Predicate, typename... Ts>
|
||||||
|
constexpr int constexpr_last() { return constexpr_impl::last(0, -1, Predicate<Ts>::value...); }
|
||||||
|
|
||||||
|
/// Return the Nth element from the parameter pack
|
||||||
|
template <size_t N, typename T, typename... Ts>
|
||||||
|
struct pack_element { using type = typename pack_element<N - 1, Ts...>::type; };
|
||||||
|
template <typename T, typename... Ts>
|
||||||
|
struct pack_element<0, T, Ts...> { using type = T; };
|
||||||
|
|
||||||
|
/// Return the one and only type which matches the predicate, or Default if none match.
|
||||||
|
/// If more than one type matches the predicate, fail at compile-time.
|
||||||
|
template <template<typename> class Predicate, typename Default, typename... Ts>
|
||||||
|
struct exactly_one {
|
||||||
|
static constexpr auto found = constexpr_sum(Predicate<Ts>::value...);
|
||||||
|
static_assert(found <= 1, "Found more than one type matching the predicate");
|
||||||
|
|
||||||
|
static constexpr auto index = found ? constexpr_first<Predicate, Ts...>() : 0;
|
||||||
|
using type = conditional_t<found, typename pack_element<index, Ts...>::type, Default>;
|
||||||
|
};
|
||||||
|
template <template<typename> class P, typename Default>
|
||||||
|
struct exactly_one<P, Default> { using type = Default; };
|
||||||
|
|
||||||
|
template <template<typename> class Predicate, typename Default, typename... Ts>
|
||||||
|
using exactly_one_t = typename exactly_one<Predicate, Default, Ts...>::type;
|
||||||
|
|
||||||
|
/// Defer the evaluation of type T until types Us are instantiated
|
||||||
|
template <typename T, typename... /*Us*/> struct deferred_type { using type = T; };
|
||||||
|
template <typename T, typename... Us> using deferred_t = typename deferred_type<T, Us...>::type;
|
||||||
|
|
||||||
|
/// Like is_base_of, but requires a strict base (i.e. `is_strict_base_of<T, T>::value == false`,
|
||||||
|
/// unlike `std::is_base_of`)
|
||||||
|
template <typename Base, typename Derived> using is_strict_base_of = bool_constant<
|
||||||
|
std::is_base_of<Base, Derived>::value && !std::is_same<Base, Derived>::value>;
|
||||||
|
|
||||||
|
/// Like is_base_of, but also requires that the base type is accessible (i.e. that a Derived pointer
|
||||||
|
/// can be converted to a Base pointer)
|
||||||
|
template <typename Base, typename Derived> using is_accessible_base_of = bool_constant<
|
||||||
|
std::is_base_of<Base, Derived>::value && std::is_convertible<Derived *, Base *>::value>;
|
||||||
|
|
||||||
|
template <template<typename...> class Base>
|
||||||
|
struct is_template_base_of_impl {
|
||||||
|
template <typename... Us> static std::true_type check(Base<Us...> *);
|
||||||
|
static std::false_type check(...);
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Check if a template is the base of a type. For example:
|
||||||
|
/// `is_template_base_of<Base, T>` is true if `struct T : Base<U> {}` where U can be anything
|
||||||
|
template <template<typename...> class Base, typename T>
|
||||||
|
#if !defined(_MSC_VER)
|
||||||
|
using is_template_base_of = decltype(is_template_base_of_impl<Base>::check((intrinsic_t<T>*)nullptr));
|
||||||
|
#else // MSVC2015 has trouble with decltype in template aliases
|
||||||
|
struct is_template_base_of : decltype(is_template_base_of_impl<Base>::check((intrinsic_t<T>*)nullptr)) { };
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/// Check if T is an instantiation of the template `Class`. For example:
|
||||||
|
/// `is_instantiation<shared_ptr, T>` is true if `T == shared_ptr<U>` where U can be anything.
|
||||||
|
template <template<typename...> class Class, typename T>
|
||||||
|
struct is_instantiation : std::false_type { };
|
||||||
|
template <template<typename...> class Class, typename... Us>
|
||||||
|
struct is_instantiation<Class, Class<Us...>> : std::true_type { };
|
||||||
|
|
||||||
|
/// Check if T is std::shared_ptr<U> where U can be anything
|
||||||
|
template <typename T> using is_shared_ptr = is_instantiation<std::shared_ptr, T>;
|
||||||
|
|
||||||
|
/// Check if T looks like an input iterator
|
||||||
|
template <typename T, typename = void> struct is_input_iterator : std::false_type {};
|
||||||
|
template <typename T>
|
||||||
|
struct is_input_iterator<T, void_t<decltype(*std::declval<T &>()), decltype(++std::declval<T &>())>>
|
||||||
|
: std::true_type {};
|
||||||
|
|
||||||
|
template <typename T> using is_function_pointer = bool_constant<
|
||||||
|
std::is_pointer<T>::value && std::is_function<typename std::remove_pointer<T>::type>::value>;
|
||||||
|
|
||||||
|
template <typename F> struct strip_function_object {
|
||||||
|
using type = typename remove_class<decltype(&F::operator())>::type;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Extracts the function signature from a function, function pointer or lambda.
|
||||||
|
template <typename Function, typename F = remove_reference_t<Function>>
|
||||||
|
using function_signature_t = conditional_t<
|
||||||
|
std::is_function<F>::value,
|
||||||
|
F,
|
||||||
|
typename conditional_t<
|
||||||
|
std::is_pointer<F>::value || std::is_member_pointer<F>::value,
|
||||||
|
std::remove_pointer<F>,
|
||||||
|
strip_function_object<F>
|
||||||
|
>::type
|
||||||
|
>;
|
||||||
|
|
||||||
|
/// Returns true if the type looks like a lambda: that is, isn't a function, pointer or member
|
||||||
|
/// pointer. Note that this can catch all sorts of other things, too; this is intended to be used
|
||||||
|
/// in a place where passing a lambda makes sense.
|
||||||
|
template <typename T> using is_lambda = satisfies_none_of<remove_reference_t<T>,
|
||||||
|
std::is_function, std::is_pointer, std::is_member_pointer>;
|
||||||
|
|
||||||
|
/// Ignore that a variable is unused in compiler warnings
|
||||||
|
inline void ignore_unused(const int *) { }
|
||||||
|
|
||||||
|
/// Apply a function over each element of a parameter pack
|
||||||
|
#ifdef __cpp_fold_expressions
|
||||||
|
#define PYBIND11_EXPAND_SIDE_EFFECTS(PATTERN) (((PATTERN), void()), ...)
|
||||||
|
#else
|
||||||
|
using expand_side_effects = bool[];
|
||||||
|
#define PYBIND11_EXPAND_SIDE_EFFECTS(PATTERN) pybind11::detail::expand_side_effects{ ((PATTERN), void(), false)..., false }
|
||||||
|
#endif
|
||||||
|
|
||||||
|
NAMESPACE_END(detail)
|
||||||
|
|
||||||
|
/// C++ bindings of builtin Python exceptions
|
||||||
|
class builtin_exception : public std::runtime_error {
|
||||||
|
public:
|
||||||
|
using std::runtime_error::runtime_error;
|
||||||
|
/// Set the error using the Python C API
|
||||||
|
virtual void set_error() const = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define PYBIND11_RUNTIME_EXCEPTION(name, type) \
|
||||||
|
class name : public builtin_exception { public: \
|
||||||
|
using builtin_exception::builtin_exception; \
|
||||||
|
name() : name("") { } \
|
||||||
|
void set_error() const override { PyErr_SetString(type, what()); } \
|
||||||
|
};
|
||||||
|
|
||||||
|
PYBIND11_RUNTIME_EXCEPTION(stop_iteration, PyExc_StopIteration)
|
||||||
|
PYBIND11_RUNTIME_EXCEPTION(index_error, PyExc_IndexError)
|
||||||
|
PYBIND11_RUNTIME_EXCEPTION(key_error, PyExc_KeyError)
|
||||||
|
PYBIND11_RUNTIME_EXCEPTION(value_error, PyExc_ValueError)
|
||||||
|
PYBIND11_RUNTIME_EXCEPTION(type_error, PyExc_TypeError)
|
||||||
|
PYBIND11_RUNTIME_EXCEPTION(buffer_error, PyExc_BufferError)
|
||||||
|
PYBIND11_RUNTIME_EXCEPTION(import_error, PyExc_ImportError)
|
||||||
|
PYBIND11_RUNTIME_EXCEPTION(cast_error, PyExc_RuntimeError) /// Thrown when pybind11::cast or handle::call fail due to a type casting error
|
||||||
|
PYBIND11_RUNTIME_EXCEPTION(reference_cast_error, PyExc_RuntimeError) /// Used internally
|
||||||
|
|
||||||
|
[[noreturn]] PYBIND11_NOINLINE inline void pybind11_fail(const char *reason) { throw std::runtime_error(reason); }
|
||||||
|
[[noreturn]] PYBIND11_NOINLINE inline void pybind11_fail(const std::string &reason) { throw std::runtime_error(reason); }
|
||||||
|
|
||||||
|
template <typename T, typename SFINAE = void> struct format_descriptor { };
|
||||||
|
|
||||||
|
NAMESPACE_BEGIN(detail)
|
||||||
|
// Returns the index of the given type in the type char array below, and in the list in numpy.h
|
||||||
|
// The order here is: bool; 8 ints ((signed,unsigned)x(8,16,32,64)bits); float,double,long double;
|
||||||
|
// complex float,double,long double. Note that the long double types only participate when long
|
||||||
|
// double is actually longer than double (it isn't under MSVC).
|
||||||
|
// NB: not only the string below but also complex.h and numpy.h rely on this order.
|
||||||
|
template <typename T, typename SFINAE = void> struct is_fmt_numeric { static constexpr bool value = false; };
|
||||||
|
template <typename T> struct is_fmt_numeric<T, enable_if_t<std::is_arithmetic<T>::value>> {
|
||||||
|
static constexpr bool value = true;
|
||||||
|
static constexpr int index = std::is_same<T, bool>::value ? 0 : 1 + (
|
||||||
|
std::is_integral<T>::value ? detail::log2(sizeof(T))*2 + std::is_unsigned<T>::value : 8 + (
|
||||||
|
std::is_same<T, double>::value ? 1 : std::is_same<T, long double>::value ? 2 : 0));
|
||||||
|
};
|
||||||
|
NAMESPACE_END(detail)
|
||||||
|
|
||||||
|
template <typename T> struct format_descriptor<T, detail::enable_if_t<std::is_arithmetic<T>::value>> {
|
||||||
|
static constexpr const char c = "?bBhHiIqQfdg"[detail::is_fmt_numeric<T>::index];
|
||||||
|
static constexpr const char value[2] = { c, '\0' };
|
||||||
|
static std::string format() { return std::string(1, c); }
|
||||||
|
};
|
||||||
|
|
||||||
|
#if !defined(PYBIND11_CPP17)
|
||||||
|
|
||||||
|
template <typename T> constexpr const char format_descriptor<
|
||||||
|
T, detail::enable_if_t<std::is_arithmetic<T>::value>>::value[2];
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/// RAII wrapper that temporarily clears any Python error state
|
||||||
|
struct error_scope {
|
||||||
|
PyObject *type, *value, *trace;
|
||||||
|
error_scope() { PyErr_Fetch(&type, &value, &trace); }
|
||||||
|
~error_scope() { PyErr_Restore(type, value, trace); }
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Dummy destructor wrapper that can be used to expose classes with a private destructor
|
||||||
|
struct nodelete { template <typename T> void operator()(T*) { } };
|
||||||
|
|
||||||
|
NAMESPACE_BEGIN(detail)
|
||||||
|
template <typename... Args>
|
||||||
|
struct overload_cast_impl {
|
||||||
|
constexpr overload_cast_impl() {} // MSVC 2015 needs this
|
||||||
|
|
||||||
|
template <typename Return>
|
||||||
|
constexpr auto operator()(Return (*pf)(Args...)) const noexcept
|
||||||
|
-> decltype(pf) { return pf; }
|
||||||
|
|
||||||
|
template <typename Return, typename Class>
|
||||||
|
constexpr auto operator()(Return (Class::*pmf)(Args...), std::false_type = {}) const noexcept
|
||||||
|
-> decltype(pmf) { return pmf; }
|
||||||
|
|
||||||
|
template <typename Return, typename Class>
|
||||||
|
constexpr auto operator()(Return (Class::*pmf)(Args...) const, std::true_type) const noexcept
|
||||||
|
-> decltype(pmf) { return pmf; }
|
||||||
|
};
|
||||||
|
NAMESPACE_END(detail)
|
||||||
|
|
||||||
|
// overload_cast requires variable templates: C++14
|
||||||
|
#if defined(PYBIND11_CPP14)
|
||||||
|
#define PYBIND11_OVERLOAD_CAST 1
|
||||||
|
/// Syntax sugar for resolving overloaded function pointers:
|
||||||
|
/// - regular: static_cast<Return (Class::*)(Arg0, Arg1, Arg2)>(&Class::func)
|
||||||
|
/// - sweet: overload_cast<Arg0, Arg1, Arg2>(&Class::func)
|
||||||
|
template <typename... Args>
|
||||||
|
static constexpr detail::overload_cast_impl<Args...> overload_cast = {};
|
||||||
|
// MSVC 2015 only accepts this particular initialization syntax for this variable template.
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/// Const member function selector for overload_cast
|
||||||
|
/// - regular: static_cast<Return (Class::*)(Arg) const>(&Class::func)
|
||||||
|
/// - sweet: overload_cast<Arg>(&Class::func, const_)
|
||||||
|
static constexpr auto const_ = std::true_type{};
|
||||||
|
|
||||||
|
#if !defined(PYBIND11_CPP14) // no overload_cast: providing something that static_assert-fails:
|
||||||
|
template <typename... Args> struct overload_cast {
|
||||||
|
static_assert(detail::deferred_t<std::false_type, Args...>::value,
|
||||||
|
"pybind11::overload_cast<...> requires compiling in C++14 mode");
|
||||||
|
};
|
||||||
|
#endif // overload_cast
|
||||||
|
|
||||||
|
NAMESPACE_BEGIN(detail)
|
||||||
|
|
||||||
|
// Adaptor for converting arbitrary container arguments into a vector; implicitly convertible from
|
||||||
|
// any standard container (or C-style array) supporting std::begin/std::end, any singleton
|
||||||
|
// arithmetic type (if T is arithmetic), or explicitly constructible from an iterator pair.
|
||||||
|
template <typename T>
|
||||||
|
class any_container {
|
||||||
|
std::vector<T> v;
|
||||||
|
public:
|
||||||
|
any_container() = default;
|
||||||
|
|
||||||
|
// Can construct from a pair of iterators
|
||||||
|
template <typename It, typename = enable_if_t<is_input_iterator<It>::value>>
|
||||||
|
any_container(It first, It last) : v(first, last) { }
|
||||||
|
|
||||||
|
// Implicit conversion constructor from any arbitrary container type with values convertible to T
|
||||||
|
template <typename Container, typename = enable_if_t<std::is_convertible<decltype(*std::begin(std::declval<const Container &>())), T>::value>>
|
||||||
|
any_container(const Container &c) : any_container(std::begin(c), std::end(c)) { }
|
||||||
|
|
||||||
|
// initializer_list's aren't deducible, so don't get matched by the above template; we need this
|
||||||
|
// to explicitly allow implicit conversion from one:
|
||||||
|
template <typename TIn, typename = enable_if_t<std::is_convertible<TIn, T>::value>>
|
||||||
|
any_container(const std::initializer_list<TIn> &c) : any_container(c.begin(), c.end()) { }
|
||||||
|
|
||||||
|
// Avoid copying if given an rvalue vector of the correct type.
|
||||||
|
any_container(std::vector<T> &&v) : v(std::move(v)) { }
|
||||||
|
|
||||||
|
// Moves the vector out of an rvalue any_container
|
||||||
|
operator std::vector<T> &&() && { return std::move(v); }
|
||||||
|
|
||||||
|
// Dereferencing obtains a reference to the underlying vector
|
||||||
|
std::vector<T> &operator*() { return v; }
|
||||||
|
const std::vector<T> &operator*() const { return v; }
|
||||||
|
|
||||||
|
// -> lets you call methods on the underlying vector
|
||||||
|
std::vector<T> *operator->() { return &v; }
|
||||||
|
const std::vector<T> *operator->() const { return &v; }
|
||||||
|
};
|
||||||
|
|
||||||
|
NAMESPACE_END(detail)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
NAMESPACE_END(PYBIND11_NAMESPACE)
|
100
3rdparty/pybind11/include/pybind11/detail/descr.h
vendored
Normal file
100
3rdparty/pybind11/include/pybind11/detail/descr.h
vendored
Normal file
@ -0,0 +1,100 @@
|
|||||||
|
/*
|
||||||
|
pybind11/detail/descr.h: Helper type for concatenating type signatures at compile time
|
||||||
|
|
||||||
|
Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch>
|
||||||
|
|
||||||
|
All rights reserved. Use of this source code is governed by a
|
||||||
|
BSD-style license that can be found in the LICENSE file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "common.h"
|
||||||
|
|
||||||
|
NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
|
||||||
|
NAMESPACE_BEGIN(detail)
|
||||||
|
|
||||||
|
#if !defined(_MSC_VER)
|
||||||
|
# define PYBIND11_DESCR_CONSTEXPR static constexpr
|
||||||
|
#else
|
||||||
|
# define PYBIND11_DESCR_CONSTEXPR const
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Concatenate type signatures at compile time */
|
||||||
|
template <size_t N, typename... Ts>
|
||||||
|
struct descr {
|
||||||
|
char text[N + 1];
|
||||||
|
|
||||||
|
constexpr descr() : text{'\0'} { }
|
||||||
|
constexpr descr(char const (&s)[N+1]) : descr(s, make_index_sequence<N>()) { }
|
||||||
|
|
||||||
|
template <size_t... Is>
|
||||||
|
constexpr descr(char const (&s)[N+1], index_sequence<Is...>) : text{s[Is]..., '\0'} { }
|
||||||
|
|
||||||
|
template <typename... Chars>
|
||||||
|
constexpr descr(char c, Chars... cs) : text{c, static_cast<char>(cs)..., '\0'} { }
|
||||||
|
|
||||||
|
static constexpr std::array<const std::type_info *, sizeof...(Ts) + 1> types() {
|
||||||
|
return {{&typeid(Ts)..., nullptr}};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <size_t N1, size_t N2, typename... Ts1, typename... Ts2, size_t... Is1, size_t... Is2>
|
||||||
|
constexpr descr<N1 + N2, Ts1..., Ts2...> plus_impl(const descr<N1, Ts1...> &a, const descr<N2, Ts2...> &b,
|
||||||
|
index_sequence<Is1...>, index_sequence<Is2...>) {
|
||||||
|
return {a.text[Is1]..., b.text[Is2]...};
|
||||||
|
}
|
||||||
|
|
||||||
|
template <size_t N1, size_t N2, typename... Ts1, typename... Ts2>
|
||||||
|
constexpr descr<N1 + N2, Ts1..., Ts2...> operator+(const descr<N1, Ts1...> &a, const descr<N2, Ts2...> &b) {
|
||||||
|
return plus_impl(a, b, make_index_sequence<N1>(), make_index_sequence<N2>());
|
||||||
|
}
|
||||||
|
|
||||||
|
template <size_t N>
|
||||||
|
constexpr descr<N - 1> _(char const(&text)[N]) { return descr<N - 1>(text); }
|
||||||
|
constexpr descr<0> _(char const(&)[1]) { return {}; }
|
||||||
|
|
||||||
|
template <size_t Rem, size_t... Digits> struct int_to_str : int_to_str<Rem/10, Rem%10, Digits...> { };
|
||||||
|
template <size_t...Digits> struct int_to_str<0, Digits...> {
|
||||||
|
static constexpr auto digits = descr<sizeof...(Digits)>(('0' + Digits)...);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Ternary description (like std::conditional)
|
||||||
|
template <bool B, size_t N1, size_t N2>
|
||||||
|
constexpr enable_if_t<B, descr<N1 - 1>> _(char const(&text1)[N1], char const(&)[N2]) {
|
||||||
|
return _(text1);
|
||||||
|
}
|
||||||
|
template <bool B, size_t N1, size_t N2>
|
||||||
|
constexpr enable_if_t<!B, descr<N2 - 1>> _(char const(&)[N1], char const(&text2)[N2]) {
|
||||||
|
return _(text2);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <bool B, typename T1, typename T2>
|
||||||
|
constexpr enable_if_t<B, T1> _(const T1 &d, const T2 &) { return d; }
|
||||||
|
template <bool B, typename T1, typename T2>
|
||||||
|
constexpr enable_if_t<!B, T2> _(const T1 &, const T2 &d) { return d; }
|
||||||
|
|
||||||
|
template <size_t Size> auto constexpr _() -> decltype(int_to_str<Size / 10, Size % 10>::digits) {
|
||||||
|
return int_to_str<Size / 10, Size % 10>::digits;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Type> constexpr descr<1, Type> _() { return {'%'}; }
|
||||||
|
|
||||||
|
constexpr descr<0> concat() { return {}; }
|
||||||
|
|
||||||
|
template <size_t N, typename... Ts>
|
||||||
|
constexpr descr<N, Ts...> concat(const descr<N, Ts...> &descr) { return descr; }
|
||||||
|
|
||||||
|
template <size_t N, typename... Ts, typename... Args>
|
||||||
|
constexpr auto concat(const descr<N, Ts...> &d, const Args &...args)
|
||||||
|
-> decltype(std::declval<descr<N + 2, Ts...>>() + concat(args...)) {
|
||||||
|
return d + _(", ") + concat(args...);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <size_t N, typename... Ts>
|
||||||
|
constexpr descr<N + 2, Ts...> type_descr(const descr<N, Ts...> &descr) {
|
||||||
|
return _("{") + descr + _("}");
|
||||||
|
}
|
||||||
|
|
||||||
|
NAMESPACE_END(detail)
|
||||||
|
NAMESPACE_END(PYBIND11_NAMESPACE)
|
335
3rdparty/pybind11/include/pybind11/detail/init.h
vendored
Normal file
335
3rdparty/pybind11/include/pybind11/detail/init.h
vendored
Normal file
@ -0,0 +1,335 @@
|
|||||||
|
/*
|
||||||
|
pybind11/detail/init.h: init factory function implementation and support code.
|
||||||
|
|
||||||
|
Copyright (c) 2017 Jason Rhinelander <jason@imaginary.ca>
|
||||||
|
|
||||||
|
All rights reserved. Use of this source code is governed by a
|
||||||
|
BSD-style license that can be found in the LICENSE file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "class.h"
|
||||||
|
|
||||||
|
NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
|
||||||
|
NAMESPACE_BEGIN(detail)
|
||||||
|
|
||||||
|
template <>
|
||||||
|
class type_caster<value_and_holder> {
|
||||||
|
public:
|
||||||
|
bool load(handle h, bool) {
|
||||||
|
value = reinterpret_cast<value_and_holder *>(h.ptr());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename> using cast_op_type = value_and_holder &;
|
||||||
|
operator value_and_holder &() { return *value; }
|
||||||
|
static constexpr auto name = _<value_and_holder>();
|
||||||
|
|
||||||
|
private:
|
||||||
|
value_and_holder *value = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
NAMESPACE_BEGIN(initimpl)
|
||||||
|
|
||||||
|
inline void no_nullptr(void *ptr) {
|
||||||
|
if (!ptr) throw type_error("pybind11::init(): factory function returned nullptr");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Implementing functions for all forms of py::init<...> and py::init(...)
|
||||||
|
template <typename Class> using Cpp = typename Class::type;
|
||||||
|
template <typename Class> using Alias = typename Class::type_alias;
|
||||||
|
template <typename Class> using Holder = typename Class::holder_type;
|
||||||
|
|
||||||
|
template <typename Class> using is_alias_constructible = std::is_constructible<Alias<Class>, Cpp<Class> &&>;
|
||||||
|
|
||||||
|
// Takes a Cpp pointer and returns true if it actually is a polymorphic Alias instance.
|
||||||
|
template <typename Class, enable_if_t<Class::has_alias, int> = 0>
|
||||||
|
bool is_alias(Cpp<Class> *ptr) {
|
||||||
|
return dynamic_cast<Alias<Class> *>(ptr) != nullptr;
|
||||||
|
}
|
||||||
|
// Failing fallback version of the above for a no-alias class (always returns false)
|
||||||
|
template <typename /*Class*/>
|
||||||
|
constexpr bool is_alias(void *) { return false; }
|
||||||
|
|
||||||
|
// Constructs and returns a new object; if the given arguments don't map to a constructor, we fall
|
||||||
|
// back to brace aggregate initiailization so that for aggregate initialization can be used with
|
||||||
|
// py::init, e.g. `py::init<int, int>` to initialize a `struct T { int a; int b; }`. For
|
||||||
|
// non-aggregate types, we need to use an ordinary T(...) constructor (invoking as `T{...}` usually
|
||||||
|
// works, but will not do the expected thing when `T` has an `initializer_list<T>` constructor).
|
||||||
|
template <typename Class, typename... Args, detail::enable_if_t<std::is_constructible<Class, Args...>::value, int> = 0>
|
||||||
|
inline Class *construct_or_initialize(Args &&...args) { return new Class(std::forward<Args>(args)...); }
|
||||||
|
template <typename Class, typename... Args, detail::enable_if_t<!std::is_constructible<Class, Args...>::value, int> = 0>
|
||||||
|
inline Class *construct_or_initialize(Args &&...args) { return new Class{std::forward<Args>(args)...}; }
|
||||||
|
|
||||||
|
// Attempts to constructs an alias using a `Alias(Cpp &&)` constructor. This allows types with
|
||||||
|
// an alias to provide only a single Cpp factory function as long as the Alias can be
|
||||||
|
// constructed from an rvalue reference of the base Cpp type. This means that Alias classes
|
||||||
|
// can, when appropriate, simply define a `Alias(Cpp &&)` constructor rather than needing to
|
||||||
|
// inherit all the base class constructors.
|
||||||
|
template <typename Class>
|
||||||
|
void construct_alias_from_cpp(std::true_type /*is_alias_constructible*/,
|
||||||
|
value_and_holder &v_h, Cpp<Class> &&base) {
|
||||||
|
v_h.value_ptr() = new Alias<Class>(std::move(base));
|
||||||
|
}
|
||||||
|
template <typename Class>
|
||||||
|
[[noreturn]] void construct_alias_from_cpp(std::false_type /*!is_alias_constructible*/,
|
||||||
|
value_and_holder &, Cpp<Class> &&) {
|
||||||
|
throw type_error("pybind11::init(): unable to convert returned instance to required "
|
||||||
|
"alias class: no `Alias<Class>(Class &&)` constructor available");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Error-generating fallback for factories that don't match one of the below construction
|
||||||
|
// mechanisms.
|
||||||
|
template <typename Class>
|
||||||
|
void construct(...) {
|
||||||
|
static_assert(!std::is_same<Class, Class>::value /* always false */,
|
||||||
|
"pybind11::init(): init function must return a compatible pointer, "
|
||||||
|
"holder, or value");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pointer return v1: the factory function returns a class pointer for a registered class.
|
||||||
|
// If we don't need an alias (because this class doesn't have one, or because the final type is
|
||||||
|
// inherited on the Python side) we can simply take over ownership. Otherwise we need to try to
|
||||||
|
// construct an Alias from the returned base instance.
|
||||||
|
template <typename Class>
|
||||||
|
void construct(value_and_holder &v_h, Cpp<Class> *ptr, bool need_alias) {
|
||||||
|
no_nullptr(ptr);
|
||||||
|
if (Class::has_alias && need_alias && !is_alias<Class>(ptr)) {
|
||||||
|
// We're going to try to construct an alias by moving the cpp type. Whether or not
|
||||||
|
// that succeeds, we still need to destroy the original cpp pointer (either the
|
||||||
|
// moved away leftover, if the alias construction works, or the value itself if we
|
||||||
|
// throw an error), but we can't just call `delete ptr`: it might have a special
|
||||||
|
// deleter, or might be shared_from_this. So we construct a holder around it as if
|
||||||
|
// it was a normal instance, then steal the holder away into a local variable; thus
|
||||||
|
// the holder and destruction happens when we leave the C++ scope, and the holder
|
||||||
|
// class gets to handle the destruction however it likes.
|
||||||
|
v_h.value_ptr() = ptr;
|
||||||
|
v_h.set_instance_registered(true); // To prevent init_instance from registering it
|
||||||
|
v_h.type->init_instance(v_h.inst, nullptr); // Set up the holder
|
||||||
|
Holder<Class> temp_holder(std::move(v_h.holder<Holder<Class>>())); // Steal the holder
|
||||||
|
v_h.type->dealloc(v_h); // Destroys the moved-out holder remains, resets value ptr to null
|
||||||
|
v_h.set_instance_registered(false);
|
||||||
|
|
||||||
|
construct_alias_from_cpp<Class>(is_alias_constructible<Class>{}, v_h, std::move(*ptr));
|
||||||
|
} else {
|
||||||
|
// Otherwise the type isn't inherited, so we don't need an Alias
|
||||||
|
v_h.value_ptr() = ptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pointer return v2: a factory that always returns an alias instance ptr. We simply take over
|
||||||
|
// ownership of the pointer.
|
||||||
|
template <typename Class, enable_if_t<Class::has_alias, int> = 0>
|
||||||
|
void construct(value_and_holder &v_h, Alias<Class> *alias_ptr, bool) {
|
||||||
|
no_nullptr(alias_ptr);
|
||||||
|
v_h.value_ptr() = static_cast<Cpp<Class> *>(alias_ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Holder return: copy its pointer, and move or copy the returned holder into the new instance's
|
||||||
|
// holder. This also handles types like std::shared_ptr<T> and std::unique_ptr<T> where T is a
|
||||||
|
// derived type (through those holder's implicit conversion from derived class holder constructors).
|
||||||
|
template <typename Class>
|
||||||
|
void construct(value_and_holder &v_h, Holder<Class> holder, bool need_alias) {
|
||||||
|
auto *ptr = holder_helper<Holder<Class>>::get(holder);
|
||||||
|
// If we need an alias, check that the held pointer is actually an alias instance
|
||||||
|
if (Class::has_alias && need_alias && !is_alias<Class>(ptr))
|
||||||
|
throw type_error("pybind11::init(): construction failed: returned holder-wrapped instance "
|
||||||
|
"is not an alias instance");
|
||||||
|
|
||||||
|
v_h.value_ptr() = ptr;
|
||||||
|
v_h.type->init_instance(v_h.inst, &holder);
|
||||||
|
}
|
||||||
|
|
||||||
|
// return-by-value version 1: returning a cpp class by value. If the class has an alias and an
|
||||||
|
// alias is required the alias must have an `Alias(Cpp &&)` constructor so that we can construct
|
||||||
|
// the alias from the base when needed (i.e. because of Python-side inheritance). When we don't
|
||||||
|
// need it, we simply move-construct the cpp value into a new instance.
|
||||||
|
template <typename Class>
|
||||||
|
void construct(value_and_holder &v_h, Cpp<Class> &&result, bool need_alias) {
|
||||||
|
static_assert(std::is_move_constructible<Cpp<Class>>::value,
|
||||||
|
"pybind11::init() return-by-value factory function requires a movable class");
|
||||||
|
if (Class::has_alias && need_alias)
|
||||||
|
construct_alias_from_cpp<Class>(is_alias_constructible<Class>{}, v_h, std::move(result));
|
||||||
|
else
|
||||||
|
v_h.value_ptr() = new Cpp<Class>(std::move(result));
|
||||||
|
}
|
||||||
|
|
||||||
|
// return-by-value version 2: returning a value of the alias type itself. We move-construct an
|
||||||
|
// Alias instance (even if no the python-side inheritance is involved). The is intended for
|
||||||
|
// cases where Alias initialization is always desired.
|
||||||
|
template <typename Class>
|
||||||
|
void construct(value_and_holder &v_h, Alias<Class> &&result, bool) {
|
||||||
|
static_assert(std::is_move_constructible<Alias<Class>>::value,
|
||||||
|
"pybind11::init() return-by-alias-value factory function requires a movable alias class");
|
||||||
|
v_h.value_ptr() = new Alias<Class>(std::move(result));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Implementing class for py::init<...>()
|
||||||
|
template <typename... Args>
|
||||||
|
struct constructor {
|
||||||
|
template <typename Class, typename... Extra, enable_if_t<!Class::has_alias, int> = 0>
|
||||||
|
static void execute(Class &cl, const Extra&... extra) {
|
||||||
|
cl.def("__init__", [](value_and_holder &v_h, Args... args) {
|
||||||
|
v_h.value_ptr() = construct_or_initialize<Cpp<Class>>(std::forward<Args>(args)...);
|
||||||
|
}, is_new_style_constructor(), extra...);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Class, typename... Extra,
|
||||||
|
enable_if_t<Class::has_alias &&
|
||||||
|
std::is_constructible<Cpp<Class>, Args...>::value, int> = 0>
|
||||||
|
static void execute(Class &cl, const Extra&... extra) {
|
||||||
|
cl.def("__init__", [](value_and_holder &v_h, Args... args) {
|
||||||
|
if (Py_TYPE(v_h.inst) == v_h.type->type)
|
||||||
|
v_h.value_ptr() = construct_or_initialize<Cpp<Class>>(std::forward<Args>(args)...);
|
||||||
|
else
|
||||||
|
v_h.value_ptr() = construct_or_initialize<Alias<Class>>(std::forward<Args>(args)...);
|
||||||
|
}, is_new_style_constructor(), extra...);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Class, typename... Extra,
|
||||||
|
enable_if_t<Class::has_alias &&
|
||||||
|
!std::is_constructible<Cpp<Class>, Args...>::value, int> = 0>
|
||||||
|
static void execute(Class &cl, const Extra&... extra) {
|
||||||
|
cl.def("__init__", [](value_and_holder &v_h, Args... args) {
|
||||||
|
v_h.value_ptr() = construct_or_initialize<Alias<Class>>(std::forward<Args>(args)...);
|
||||||
|
}, is_new_style_constructor(), extra...);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Implementing class for py::init_alias<...>()
|
||||||
|
template <typename... Args> struct alias_constructor {
|
||||||
|
template <typename Class, typename... Extra,
|
||||||
|
enable_if_t<Class::has_alias && std::is_constructible<Alias<Class>, Args...>::value, int> = 0>
|
||||||
|
static void execute(Class &cl, const Extra&... extra) {
|
||||||
|
cl.def("__init__", [](value_and_holder &v_h, Args... args) {
|
||||||
|
v_h.value_ptr() = construct_or_initialize<Alias<Class>>(std::forward<Args>(args)...);
|
||||||
|
}, is_new_style_constructor(), extra...);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Implementation class for py::init(Func) and py::init(Func, AliasFunc)
|
||||||
|
template <typename CFunc, typename AFunc = void_type (*)(),
|
||||||
|
typename = function_signature_t<CFunc>, typename = function_signature_t<AFunc>>
|
||||||
|
struct factory;
|
||||||
|
|
||||||
|
// Specialization for py::init(Func)
|
||||||
|
template <typename Func, typename Return, typename... Args>
|
||||||
|
struct factory<Func, void_type (*)(), Return(Args...)> {
|
||||||
|
remove_reference_t<Func> class_factory;
|
||||||
|
|
||||||
|
factory(Func &&f) : class_factory(std::forward<Func>(f)) { }
|
||||||
|
|
||||||
|
// The given class either has no alias or has no separate alias factory;
|
||||||
|
// this always constructs the class itself. If the class is registered with an alias
|
||||||
|
// type and an alias instance is needed (i.e. because the final type is a Python class
|
||||||
|
// inheriting from the C++ type) the returned value needs to either already be an alias
|
||||||
|
// instance, or the alias needs to be constructible from a `Class &&` argument.
|
||||||
|
template <typename Class, typename... Extra>
|
||||||
|
void execute(Class &cl, const Extra &...extra) && {
|
||||||
|
#if defined(PYBIND11_CPP14)
|
||||||
|
cl.def("__init__", [func = std::move(class_factory)]
|
||||||
|
#else
|
||||||
|
auto &func = class_factory;
|
||||||
|
cl.def("__init__", [func]
|
||||||
|
#endif
|
||||||
|
(value_and_holder &v_h, Args... args) {
|
||||||
|
construct<Class>(v_h, func(std::forward<Args>(args)...),
|
||||||
|
Py_TYPE(v_h.inst) != v_h.type->type);
|
||||||
|
}, is_new_style_constructor(), extra...);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Specialization for py::init(Func, AliasFunc)
|
||||||
|
template <typename CFunc, typename AFunc,
|
||||||
|
typename CReturn, typename... CArgs, typename AReturn, typename... AArgs>
|
||||||
|
struct factory<CFunc, AFunc, CReturn(CArgs...), AReturn(AArgs...)> {
|
||||||
|
static_assert(sizeof...(CArgs) == sizeof...(AArgs),
|
||||||
|
"pybind11::init(class_factory, alias_factory): class and alias factories "
|
||||||
|
"must have identical argument signatures");
|
||||||
|
static_assert(all_of<std::is_same<CArgs, AArgs>...>::value,
|
||||||
|
"pybind11::init(class_factory, alias_factory): class and alias factories "
|
||||||
|
"must have identical argument signatures");
|
||||||
|
|
||||||
|
remove_reference_t<CFunc> class_factory;
|
||||||
|
remove_reference_t<AFunc> alias_factory;
|
||||||
|
|
||||||
|
factory(CFunc &&c, AFunc &&a)
|
||||||
|
: class_factory(std::forward<CFunc>(c)), alias_factory(std::forward<AFunc>(a)) { }
|
||||||
|
|
||||||
|
// The class factory is called when the `self` type passed to `__init__` is the direct
|
||||||
|
// class (i.e. not inherited), the alias factory when `self` is a Python-side subtype.
|
||||||
|
template <typename Class, typename... Extra>
|
||||||
|
void execute(Class &cl, const Extra&... extra) && {
|
||||||
|
static_assert(Class::has_alias, "The two-argument version of `py::init()` can "
|
||||||
|
"only be used if the class has an alias");
|
||||||
|
#if defined(PYBIND11_CPP14)
|
||||||
|
cl.def("__init__", [class_func = std::move(class_factory), alias_func = std::move(alias_factory)]
|
||||||
|
#else
|
||||||
|
auto &class_func = class_factory;
|
||||||
|
auto &alias_func = alias_factory;
|
||||||
|
cl.def("__init__", [class_func, alias_func]
|
||||||
|
#endif
|
||||||
|
(value_and_holder &v_h, CArgs... args) {
|
||||||
|
if (Py_TYPE(v_h.inst) == v_h.type->type)
|
||||||
|
// If the instance type equals the registered type we don't have inheritance, so
|
||||||
|
// don't need the alias and can construct using the class function:
|
||||||
|
construct<Class>(v_h, class_func(std::forward<CArgs>(args)...), false);
|
||||||
|
else
|
||||||
|
construct<Class>(v_h, alias_func(std::forward<CArgs>(args)...), true);
|
||||||
|
}, is_new_style_constructor(), extra...);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Set just the C++ state. Same as `__init__`.
|
||||||
|
template <typename Class, typename T>
|
||||||
|
void setstate(value_and_holder &v_h, T &&result, bool need_alias) {
|
||||||
|
construct<Class>(v_h, std::forward<T>(result), need_alias);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Set both the C++ and Python states
|
||||||
|
template <typename Class, typename T, typename O,
|
||||||
|
enable_if_t<std::is_convertible<O, handle>::value, int> = 0>
|
||||||
|
void setstate(value_and_holder &v_h, std::pair<T, O> &&result, bool need_alias) {
|
||||||
|
construct<Class>(v_h, std::move(result.first), need_alias);
|
||||||
|
setattr((PyObject *) v_h.inst, "__dict__", result.second);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Implementation for py::pickle(GetState, SetState)
|
||||||
|
template <typename Get, typename Set,
|
||||||
|
typename = function_signature_t<Get>, typename = function_signature_t<Set>>
|
||||||
|
struct pickle_factory;
|
||||||
|
|
||||||
|
template <typename Get, typename Set,
|
||||||
|
typename RetState, typename Self, typename NewInstance, typename ArgState>
|
||||||
|
struct pickle_factory<Get, Set, RetState(Self), NewInstance(ArgState)> {
|
||||||
|
static_assert(std::is_same<intrinsic_t<RetState>, intrinsic_t<ArgState>>::value,
|
||||||
|
"The type returned by `__getstate__` must be the same "
|
||||||
|
"as the argument accepted by `__setstate__`");
|
||||||
|
|
||||||
|
remove_reference_t<Get> get;
|
||||||
|
remove_reference_t<Set> set;
|
||||||
|
|
||||||
|
pickle_factory(Get get, Set set)
|
||||||
|
: get(std::forward<Get>(get)), set(std::forward<Set>(set)) { }
|
||||||
|
|
||||||
|
template <typename Class, typename... Extra>
|
||||||
|
void execute(Class &cl, const Extra &...extra) && {
|
||||||
|
cl.def("__getstate__", std::move(get));
|
||||||
|
|
||||||
|
#if defined(PYBIND11_CPP14)
|
||||||
|
cl.def("__setstate__", [func = std::move(set)]
|
||||||
|
#else
|
||||||
|
auto &func = set;
|
||||||
|
cl.def("__setstate__", [func]
|
||||||
|
#endif
|
||||||
|
(value_and_holder &v_h, ArgState state) {
|
||||||
|
setstate<Class>(v_h, func(std::forward<ArgState>(state)),
|
||||||
|
Py_TYPE(v_h.inst) != v_h.type->type);
|
||||||
|
}, is_new_style_constructor(), extra...);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
NAMESPACE_END(initimpl)
|
||||||
|
NAMESPACE_END(detail)
|
||||||
|
NAMESPACE_END(pybind11)
|
349
3rdparty/pybind11/include/pybind11/detail/internals.h
vendored
Normal file
349
3rdparty/pybind11/include/pybind11/detail/internals.h
vendored
Normal file
@ -0,0 +1,349 @@
|
|||||||
|
/*
|
||||||
|
pybind11/detail/internals.h: Internal data structure and related functions
|
||||||
|
|
||||||
|
Copyright (c) 2017 Wenzel Jakob <wenzel.jakob@epfl.ch>
|
||||||
|
|
||||||
|
All rights reserved. Use of this source code is governed by a
|
||||||
|
BSD-style license that can be found in the LICENSE file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "../pytypes.h"
|
||||||
|
|
||||||
|
NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
|
||||||
|
NAMESPACE_BEGIN(detail)
|
||||||
|
// Forward declarations
|
||||||
|
inline PyTypeObject *make_static_property_type();
|
||||||
|
inline PyTypeObject *make_default_metaclass();
|
||||||
|
inline PyObject *make_object_base_type(PyTypeObject *metaclass);
|
||||||
|
|
||||||
|
// The old Python Thread Local Storage (TLS) API is deprecated in Python 3.7 in favor of the new
|
||||||
|
// Thread Specific Storage (TSS) API.
|
||||||
|
#if PY_VERSION_HEX >= 0x03070000
|
||||||
|
# define PYBIND11_TLS_KEY_INIT(var) Py_tss_t *var = nullptr
|
||||||
|
# define PYBIND11_TLS_GET_VALUE(key) PyThread_tss_get((key))
|
||||||
|
# define PYBIND11_TLS_REPLACE_VALUE(key, value) PyThread_tss_set((key), (value))
|
||||||
|
# define PYBIND11_TLS_DELETE_VALUE(key) PyThread_tss_set((key), nullptr)
|
||||||
|
# define PYBIND11_TLS_FREE(key) PyThread_tss_free(key)
|
||||||
|
#else
|
||||||
|
// Usually an int but a long on Cygwin64 with Python 3.x
|
||||||
|
# define PYBIND11_TLS_KEY_INIT(var) decltype(PyThread_create_key()) var = 0
|
||||||
|
# define PYBIND11_TLS_GET_VALUE(key) PyThread_get_key_value((key))
|
||||||
|
# if PY_MAJOR_VERSION < 3
|
||||||
|
# define PYBIND11_TLS_DELETE_VALUE(key) \
|
||||||
|
PyThread_delete_key_value(key)
|
||||||
|
# define PYBIND11_TLS_REPLACE_VALUE(key, value) \
|
||||||
|
do { \
|
||||||
|
PyThread_delete_key_value((key)); \
|
||||||
|
PyThread_set_key_value((key), (value)); \
|
||||||
|
} while (false)
|
||||||
|
# else
|
||||||
|
# define PYBIND11_TLS_DELETE_VALUE(key) \
|
||||||
|
PyThread_set_key_value((key), nullptr)
|
||||||
|
# define PYBIND11_TLS_REPLACE_VALUE(key, value) \
|
||||||
|
PyThread_set_key_value((key), (value))
|
||||||
|
# endif
|
||||||
|
# define PYBIND11_TLS_FREE(key) (void)key
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Python loads modules by default with dlopen with the RTLD_LOCAL flag; under libc++ and possibly
|
||||||
|
// other STLs, this means `typeid(A)` from one module won't equal `typeid(A)` from another module
|
||||||
|
// even when `A` is the same, non-hidden-visibility type (e.g. from a common include). Under
|
||||||
|
// libstdc++, this doesn't happen: equality and the type_index hash are based on the type name,
|
||||||
|
// which works. If not under a known-good stl, provide our own name-based hash and equality
|
||||||
|
// functions that use the type name.
|
||||||
|
#if defined(__GLIBCXX__)
|
||||||
|
inline bool same_type(const std::type_info &lhs, const std::type_info &rhs) { return lhs == rhs; }
|
||||||
|
using type_hash = std::hash<std::type_index>;
|
||||||
|
using type_equal_to = std::equal_to<std::type_index>;
|
||||||
|
#else
|
||||||
|
inline bool same_type(const std::type_info &lhs, const std::type_info &rhs) {
|
||||||
|
return lhs.name() == rhs.name() || std::strcmp(lhs.name(), rhs.name()) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct type_hash {
|
||||||
|
size_t operator()(const std::type_index &t) const {
|
||||||
|
size_t hash = 5381;
|
||||||
|
const char *ptr = t.name();
|
||||||
|
while (auto c = static_cast<unsigned char>(*ptr++))
|
||||||
|
hash = (hash * 33) ^ c;
|
||||||
|
return hash;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct type_equal_to {
|
||||||
|
bool operator()(const std::type_index &lhs, const std::type_index &rhs) const {
|
||||||
|
return lhs.name() == rhs.name() || std::strcmp(lhs.name(), rhs.name()) == 0;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
template <typename value_type>
|
||||||
|
using type_map = std::unordered_map<std::type_index, value_type, type_hash, type_equal_to>;
|
||||||
|
|
||||||
|
struct overload_hash {
|
||||||
|
inline size_t operator()(const std::pair<const PyObject *, const char *>& v) const {
|
||||||
|
size_t value = std::hash<const void *>()(v.first);
|
||||||
|
value ^= std::hash<const void *>()(v.second) + 0x9e3779b9 + (value<<6) + (value>>2);
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Internal data structure used to track registered instances and types.
|
||||||
|
/// Whenever binary incompatible changes are made to this structure,
|
||||||
|
/// `PYBIND11_INTERNALS_VERSION` must be incremented.
|
||||||
|
struct internals {
|
||||||
|
type_map<type_info *> registered_types_cpp; // std::type_index -> pybind11's type information
|
||||||
|
std::unordered_map<PyTypeObject *, std::vector<type_info *>> registered_types_py; // PyTypeObject* -> base type_info(s)
|
||||||
|
std::unordered_multimap<const void *, instance*> registered_instances; // void * -> instance*
|
||||||
|
std::unordered_set<std::pair<const PyObject *, const char *>, overload_hash> inactive_overload_cache;
|
||||||
|
type_map<std::vector<bool (*)(PyObject *, void *&)>> direct_conversions;
|
||||||
|
std::unordered_map<const PyObject *, std::vector<PyObject *>> patients;
|
||||||
|
std::forward_list<void (*) (std::exception_ptr)> registered_exception_translators;
|
||||||
|
std::unordered_map<std::string, void *> shared_data; // Custom data to be shared across extensions
|
||||||
|
std::vector<PyObject *> loader_patient_stack; // Used by `loader_life_support`
|
||||||
|
std::forward_list<std::string> static_strings; // Stores the std::strings backing detail::c_str()
|
||||||
|
PyTypeObject *static_property_type;
|
||||||
|
PyTypeObject *default_metaclass;
|
||||||
|
PyObject *instance_base;
|
||||||
|
#if defined(WITH_THREAD)
|
||||||
|
PYBIND11_TLS_KEY_INIT(tstate);
|
||||||
|
PyInterpreterState *istate = nullptr;
|
||||||
|
~internals() {
|
||||||
|
// This destructor is called *after* Py_Finalize() in finalize_interpreter().
|
||||||
|
// That *SHOULD BE* fine. The following details what happens whe PyThread_tss_free is called.
|
||||||
|
// PYBIND11_TLS_FREE is PyThread_tss_free on python 3.7+. On older python, it does nothing.
|
||||||
|
// PyThread_tss_free calls PyThread_tss_delete and PyMem_RawFree.
|
||||||
|
// PyThread_tss_delete just calls TlsFree (on Windows) or pthread_key_delete (on *NIX). Neither
|
||||||
|
// of those have anything to do with CPython internals.
|
||||||
|
// PyMem_RawFree *requires* that the `tstate` be allocated with the CPython allocator.
|
||||||
|
PYBIND11_TLS_FREE(tstate);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Additional type information which does not fit into the PyTypeObject.
|
||||||
|
/// Changes to this struct also require bumping `PYBIND11_INTERNALS_VERSION`.
|
||||||
|
struct type_info {
|
||||||
|
PyTypeObject *type;
|
||||||
|
const std::type_info *cpptype;
|
||||||
|
size_t type_size, type_align, holder_size_in_ptrs;
|
||||||
|
void *(*operator_new)(size_t);
|
||||||
|
void (*init_instance)(instance *, const void *);
|
||||||
|
void (*dealloc)(value_and_holder &v_h);
|
||||||
|
std::vector<PyObject *(*)(PyObject *, PyTypeObject *)> implicit_conversions;
|
||||||
|
std::vector<std::pair<const std::type_info *, void *(*)(void *)>> implicit_casts;
|
||||||
|
std::vector<bool (*)(PyObject *, void *&)> *direct_conversions;
|
||||||
|
buffer_info *(*get_buffer)(PyObject *, void *) = nullptr;
|
||||||
|
void *get_buffer_data = nullptr;
|
||||||
|
void *(*module_local_load)(PyObject *, const type_info *) = nullptr;
|
||||||
|
/* A simple type never occurs as a (direct or indirect) parent
|
||||||
|
* of a class that makes use of multiple inheritance */
|
||||||
|
bool simple_type : 1;
|
||||||
|
/* True if there is no multiple inheritance in this type's inheritance tree */
|
||||||
|
bool simple_ancestors : 1;
|
||||||
|
/* for base vs derived holder_type checks */
|
||||||
|
bool default_holder : 1;
|
||||||
|
/* true if this is a type registered with py::module_local */
|
||||||
|
bool module_local : 1;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Tracks the `internals` and `type_info` ABI version independent of the main library version
|
||||||
|
#define PYBIND11_INTERNALS_VERSION 4
|
||||||
|
|
||||||
|
/// On MSVC, debug and release builds are not ABI-compatible!
|
||||||
|
#if defined(_MSC_VER) && defined(_DEBUG)
|
||||||
|
# define PYBIND11_BUILD_TYPE "_debug"
|
||||||
|
#else
|
||||||
|
# define PYBIND11_BUILD_TYPE ""
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/// Let's assume that different compilers are ABI-incompatible.
|
||||||
|
#if defined(_MSC_VER)
|
||||||
|
# define PYBIND11_COMPILER_TYPE "_msvc"
|
||||||
|
#elif defined(__INTEL_COMPILER)
|
||||||
|
# define PYBIND11_COMPILER_TYPE "_icc"
|
||||||
|
#elif defined(__clang__)
|
||||||
|
# define PYBIND11_COMPILER_TYPE "_clang"
|
||||||
|
#elif defined(__PGI)
|
||||||
|
# define PYBIND11_COMPILER_TYPE "_pgi"
|
||||||
|
#elif defined(__MINGW32__)
|
||||||
|
# define PYBIND11_COMPILER_TYPE "_mingw"
|
||||||
|
#elif defined(__CYGWIN__)
|
||||||
|
# define PYBIND11_COMPILER_TYPE "_gcc_cygwin"
|
||||||
|
#elif defined(__GNUC__)
|
||||||
|
# define PYBIND11_COMPILER_TYPE "_gcc"
|
||||||
|
#else
|
||||||
|
# define PYBIND11_COMPILER_TYPE "_unknown"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(_LIBCPP_VERSION)
|
||||||
|
# define PYBIND11_STDLIB "_libcpp"
|
||||||
|
#elif defined(__GLIBCXX__) || defined(__GLIBCPP__)
|
||||||
|
# define PYBIND11_STDLIB "_libstdcpp"
|
||||||
|
#else
|
||||||
|
# define PYBIND11_STDLIB ""
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/// On Linux/OSX, changes in __GXX_ABI_VERSION__ indicate ABI incompatibility.
|
||||||
|
#if defined(__GXX_ABI_VERSION)
|
||||||
|
# define PYBIND11_BUILD_ABI "_cxxabi" PYBIND11_TOSTRING(__GXX_ABI_VERSION)
|
||||||
|
#else
|
||||||
|
# define PYBIND11_BUILD_ABI ""
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(WITH_THREAD)
|
||||||
|
# define PYBIND11_INTERNALS_KIND ""
|
||||||
|
#else
|
||||||
|
# define PYBIND11_INTERNALS_KIND "_without_thread"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define PYBIND11_INTERNALS_ID "__pybind11_internals_v" \
|
||||||
|
PYBIND11_TOSTRING(PYBIND11_INTERNALS_VERSION) PYBIND11_INTERNALS_KIND PYBIND11_COMPILER_TYPE PYBIND11_STDLIB PYBIND11_BUILD_ABI PYBIND11_BUILD_TYPE "__"
|
||||||
|
|
||||||
|
#define PYBIND11_MODULE_LOCAL_ID "__pybind11_module_local_v" \
|
||||||
|
PYBIND11_TOSTRING(PYBIND11_INTERNALS_VERSION) PYBIND11_INTERNALS_KIND PYBIND11_COMPILER_TYPE PYBIND11_STDLIB PYBIND11_BUILD_ABI PYBIND11_BUILD_TYPE "__"
|
||||||
|
|
||||||
|
/// Each module locally stores a pointer to the `internals` data. The data
|
||||||
|
/// itself is shared among modules with the same `PYBIND11_INTERNALS_ID`.
|
||||||
|
inline internals **&get_internals_pp() {
|
||||||
|
static internals **internals_pp = nullptr;
|
||||||
|
return internals_pp;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void translate_exception(std::exception_ptr p) {
|
||||||
|
try {
|
||||||
|
if (p) std::rethrow_exception(p);
|
||||||
|
} catch (error_already_set &e) { e.restore(); return;
|
||||||
|
} catch (const builtin_exception &e) { e.set_error(); return;
|
||||||
|
} catch (const std::bad_alloc &e) { PyErr_SetString(PyExc_MemoryError, e.what()); return;
|
||||||
|
} catch (const std::domain_error &e) { PyErr_SetString(PyExc_ValueError, e.what()); return;
|
||||||
|
} catch (const std::invalid_argument &e) { PyErr_SetString(PyExc_ValueError, e.what()); return;
|
||||||
|
} catch (const std::length_error &e) { PyErr_SetString(PyExc_ValueError, e.what()); return;
|
||||||
|
} catch (const std::out_of_range &e) { PyErr_SetString(PyExc_IndexError, e.what()); return;
|
||||||
|
} catch (const std::range_error &e) { PyErr_SetString(PyExc_ValueError, e.what()); return;
|
||||||
|
} catch (const std::overflow_error &e) { PyErr_SetString(PyExc_OverflowError, e.what()); return;
|
||||||
|
} catch (const std::exception &e) { PyErr_SetString(PyExc_RuntimeError, e.what()); return;
|
||||||
|
} catch (...) {
|
||||||
|
PyErr_SetString(PyExc_RuntimeError, "Caught an unknown exception!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#if !defined(__GLIBCXX__)
|
||||||
|
inline void translate_local_exception(std::exception_ptr p) {
|
||||||
|
try {
|
||||||
|
if (p) std::rethrow_exception(p);
|
||||||
|
} catch (error_already_set &e) { e.restore(); return;
|
||||||
|
} catch (const builtin_exception &e) { e.set_error(); return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/// Return a reference to the current `internals` data
|
||||||
|
PYBIND11_NOINLINE inline internals &get_internals() {
|
||||||
|
auto **&internals_pp = get_internals_pp();
|
||||||
|
if (internals_pp && *internals_pp)
|
||||||
|
return **internals_pp;
|
||||||
|
|
||||||
|
// Ensure that the GIL is held since we will need to make Python calls.
|
||||||
|
// Cannot use py::gil_scoped_acquire here since that constructor calls get_internals.
|
||||||
|
struct gil_scoped_acquire_local {
|
||||||
|
gil_scoped_acquire_local() : state (PyGILState_Ensure()) {}
|
||||||
|
~gil_scoped_acquire_local() { PyGILState_Release(state); }
|
||||||
|
const PyGILState_STATE state;
|
||||||
|
} gil;
|
||||||
|
|
||||||
|
constexpr auto *id = PYBIND11_INTERNALS_ID;
|
||||||
|
auto builtins = handle(PyEval_GetBuiltins());
|
||||||
|
if (builtins.contains(id) && isinstance<capsule>(builtins[id])) {
|
||||||
|
internals_pp = static_cast<internals **>(capsule(builtins[id]));
|
||||||
|
|
||||||
|
// We loaded builtins through python's builtins, which means that our `error_already_set`
|
||||||
|
// and `builtin_exception` may be different local classes than the ones set up in the
|
||||||
|
// initial exception translator, below, so add another for our local exception classes.
|
||||||
|
//
|
||||||
|
// libstdc++ doesn't require this (types there are identified only by name)
|
||||||
|
#if !defined(__GLIBCXX__)
|
||||||
|
(*internals_pp)->registered_exception_translators.push_front(&translate_local_exception);
|
||||||
|
#endif
|
||||||
|
} else {
|
||||||
|
if (!internals_pp) internals_pp = new internals*();
|
||||||
|
auto *&internals_ptr = *internals_pp;
|
||||||
|
internals_ptr = new internals();
|
||||||
|
#if defined(WITH_THREAD)
|
||||||
|
PyEval_InitThreads();
|
||||||
|
PyThreadState *tstate = PyThreadState_Get();
|
||||||
|
#if PY_VERSION_HEX >= 0x03070000
|
||||||
|
internals_ptr->tstate = PyThread_tss_alloc();
|
||||||
|
if (!internals_ptr->tstate || PyThread_tss_create(internals_ptr->tstate))
|
||||||
|
pybind11_fail("get_internals: could not successfully initialize the TSS key!");
|
||||||
|
PyThread_tss_set(internals_ptr->tstate, tstate);
|
||||||
|
#else
|
||||||
|
internals_ptr->tstate = PyThread_create_key();
|
||||||
|
if (internals_ptr->tstate == -1)
|
||||||
|
pybind11_fail("get_internals: could not successfully initialize the TLS key!");
|
||||||
|
PyThread_set_key_value(internals_ptr->tstate, tstate);
|
||||||
|
#endif
|
||||||
|
internals_ptr->istate = tstate->interp;
|
||||||
|
#endif
|
||||||
|
builtins[id] = capsule(internals_pp);
|
||||||
|
internals_ptr->registered_exception_translators.push_front(&translate_exception);
|
||||||
|
internals_ptr->static_property_type = make_static_property_type();
|
||||||
|
internals_ptr->default_metaclass = make_default_metaclass();
|
||||||
|
internals_ptr->instance_base = make_object_base_type(internals_ptr->default_metaclass);
|
||||||
|
}
|
||||||
|
return **internals_pp;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Works like `internals.registered_types_cpp`, but for module-local registered types:
|
||||||
|
inline type_map<type_info *> ®istered_local_types_cpp() {
|
||||||
|
static type_map<type_info *> locals{};
|
||||||
|
return locals;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Constructs a std::string with the given arguments, stores it in `internals`, and returns its
|
||||||
|
/// `c_str()`. Such strings objects have a long storage duration -- the internal strings are only
|
||||||
|
/// cleared when the program exits or after interpreter shutdown (when embedding), and so are
|
||||||
|
/// suitable for c-style strings needed by Python internals (such as PyTypeObject's tp_name).
|
||||||
|
template <typename... Args>
|
||||||
|
const char *c_str(Args &&...args) {
|
||||||
|
auto &strings = get_internals().static_strings;
|
||||||
|
strings.emplace_front(std::forward<Args>(args)...);
|
||||||
|
return strings.front().c_str();
|
||||||
|
}
|
||||||
|
|
||||||
|
NAMESPACE_END(detail)
|
||||||
|
|
||||||
|
/// Returns a named pointer that is shared among all extension modules (using the same
|
||||||
|
/// pybind11 version) running in the current interpreter. Names starting with underscores
|
||||||
|
/// are reserved for internal usage. Returns `nullptr` if no matching entry was found.
|
||||||
|
inline PYBIND11_NOINLINE void *get_shared_data(const std::string &name) {
|
||||||
|
auto &internals = detail::get_internals();
|
||||||
|
auto it = internals.shared_data.find(name);
|
||||||
|
return it != internals.shared_data.end() ? it->second : nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Set the shared data that can be later recovered by `get_shared_data()`.
|
||||||
|
inline PYBIND11_NOINLINE void *set_shared_data(const std::string &name, void *data) {
|
||||||
|
detail::get_internals().shared_data[name] = data;
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns a typed reference to a shared data entry (by using `get_shared_data()`) if
|
||||||
|
/// such entry exists. Otherwise, a new object of default-constructible type `T` is
|
||||||
|
/// added to the shared data under the given name and a reference to it is returned.
|
||||||
|
template<typename T>
|
||||||
|
T &get_or_create_shared_data(const std::string &name) {
|
||||||
|
auto &internals = detail::get_internals();
|
||||||
|
auto it = internals.shared_data.find(name);
|
||||||
|
T *ptr = (T *) (it != internals.shared_data.end() ? it->second : nullptr);
|
||||||
|
if (!ptr) {
|
||||||
|
ptr = new T();
|
||||||
|
internals.shared_data[name] = ptr;
|
||||||
|
}
|
||||||
|
return *ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
NAMESPACE_END(PYBIND11_NAMESPACE)
|
55
3rdparty/pybind11/include/pybind11/detail/typeid.h
vendored
Normal file
55
3rdparty/pybind11/include/pybind11/detail/typeid.h
vendored
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
/*
|
||||||
|
pybind11/detail/typeid.h: Compiler-independent access to type identifiers
|
||||||
|
|
||||||
|
Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch>
|
||||||
|
|
||||||
|
All rights reserved. Use of this source code is governed by a
|
||||||
|
BSD-style license that can be found in the LICENSE file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <cstdio>
|
||||||
|
#include <cstdlib>
|
||||||
|
|
||||||
|
#if defined(__GNUG__)
|
||||||
|
#include <cxxabi.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "common.h"
|
||||||
|
|
||||||
|
NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
|
||||||
|
NAMESPACE_BEGIN(detail)
|
||||||
|
/// Erase all occurrences of a substring
|
||||||
|
inline void erase_all(std::string &string, const std::string &search) {
|
||||||
|
for (size_t pos = 0;;) {
|
||||||
|
pos = string.find(search, pos);
|
||||||
|
if (pos == std::string::npos) break;
|
||||||
|
string.erase(pos, search.length());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
PYBIND11_NOINLINE inline void clean_type_id(std::string &name) {
|
||||||
|
#if defined(__GNUG__)
|
||||||
|
int status = 0;
|
||||||
|
std::unique_ptr<char, void (*)(void *)> res {
|
||||||
|
abi::__cxa_demangle(name.c_str(), nullptr, nullptr, &status), std::free };
|
||||||
|
if (status == 0)
|
||||||
|
name = res.get();
|
||||||
|
#else
|
||||||
|
detail::erase_all(name, "class ");
|
||||||
|
detail::erase_all(name, "struct ");
|
||||||
|
detail::erase_all(name, "enum ");
|
||||||
|
#endif
|
||||||
|
detail::erase_all(name, "pybind11::");
|
||||||
|
}
|
||||||
|
NAMESPACE_END(detail)
|
||||||
|
|
||||||
|
/// Return a string representation of a C++ type
|
||||||
|
template <typename T> static std::string type_id() {
|
||||||
|
std::string name(typeid(T).name());
|
||||||
|
detail::clean_type_id(name);
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
NAMESPACE_END(PYBIND11_NAMESPACE)
|
607
3rdparty/pybind11/include/pybind11/eigen.h
vendored
Normal file
607
3rdparty/pybind11/include/pybind11/eigen.h
vendored
Normal file
@ -0,0 +1,607 @@
|
|||||||
|
/*
|
||||||
|
pybind11/eigen.h: Transparent conversion for dense and sparse Eigen matrices
|
||||||
|
|
||||||
|
Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch>
|
||||||
|
|
||||||
|
All rights reserved. Use of this source code is governed by a
|
||||||
|
BSD-style license that can be found in the LICENSE file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "numpy.h"
|
||||||
|
|
||||||
|
#if defined(__INTEL_COMPILER)
|
||||||
|
# pragma warning(disable: 1682) // implicit conversion of a 64-bit integral type to a smaller integral type (potential portability problem)
|
||||||
|
#elif defined(__GNUG__) || defined(__clang__)
|
||||||
|
# pragma GCC diagnostic push
|
||||||
|
# pragma GCC diagnostic ignored "-Wconversion"
|
||||||
|
# pragma GCC diagnostic ignored "-Wdeprecated-declarations"
|
||||||
|
# ifdef __clang__
|
||||||
|
// Eigen generates a bunch of implicit-copy-constructor-is-deprecated warnings with -Wdeprecated
|
||||||
|
// under Clang, so disable that warning here:
|
||||||
|
# pragma GCC diagnostic ignored "-Wdeprecated"
|
||||||
|
# endif
|
||||||
|
# if __GNUC__ >= 7
|
||||||
|
# pragma GCC diagnostic ignored "-Wint-in-bool-context"
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(_MSC_VER)
|
||||||
|
# pragma warning(push)
|
||||||
|
# pragma warning(disable: 4127) // warning C4127: Conditional expression is constant
|
||||||
|
# pragma warning(disable: 4996) // warning C4996: std::unary_negate is deprecated in C++17
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <Eigen/Core>
|
||||||
|
#include <Eigen/SparseCore>
|
||||||
|
|
||||||
|
// Eigen prior to 3.2.7 doesn't have proper move constructors--but worse, some classes get implicit
|
||||||
|
// move constructors that break things. We could detect this an explicitly copy, but an extra copy
|
||||||
|
// of matrices seems highly undesirable.
|
||||||
|
static_assert(EIGEN_VERSION_AT_LEAST(3,2,7), "Eigen support in pybind11 requires Eigen >= 3.2.7");
|
||||||
|
|
||||||
|
NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
|
||||||
|
|
||||||
|
// Provide a convenience alias for easier pass-by-ref usage with fully dynamic strides:
|
||||||
|
using EigenDStride = Eigen::Stride<Eigen::Dynamic, Eigen::Dynamic>;
|
||||||
|
template <typename MatrixType> using EigenDRef = Eigen::Ref<MatrixType, 0, EigenDStride>;
|
||||||
|
template <typename MatrixType> using EigenDMap = Eigen::Map<MatrixType, 0, EigenDStride>;
|
||||||
|
|
||||||
|
NAMESPACE_BEGIN(detail)
|
||||||
|
|
||||||
|
#if EIGEN_VERSION_AT_LEAST(3,3,0)
|
||||||
|
using EigenIndex = Eigen::Index;
|
||||||
|
#else
|
||||||
|
using EigenIndex = EIGEN_DEFAULT_DENSE_INDEX_TYPE;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Matches Eigen::Map, Eigen::Ref, blocks, etc:
|
||||||
|
template <typename T> using is_eigen_dense_map = all_of<is_template_base_of<Eigen::DenseBase, T>, std::is_base_of<Eigen::MapBase<T, Eigen::ReadOnlyAccessors>, T>>;
|
||||||
|
template <typename T> using is_eigen_mutable_map = std::is_base_of<Eigen::MapBase<T, Eigen::WriteAccessors>, T>;
|
||||||
|
template <typename T> using is_eigen_dense_plain = all_of<negation<is_eigen_dense_map<T>>, is_template_base_of<Eigen::PlainObjectBase, T>>;
|
||||||
|
template <typename T> using is_eigen_sparse = is_template_base_of<Eigen::SparseMatrixBase, T>;
|
||||||
|
// Test for objects inheriting from EigenBase<Derived> that aren't captured by the above. This
|
||||||
|
// basically covers anything that can be assigned to a dense matrix but that don't have a typical
|
||||||
|
// matrix data layout that can be copied from their .data(). For example, DiagonalMatrix and
|
||||||
|
// SelfAdjointView fall into this category.
|
||||||
|
template <typename T> using is_eigen_other = all_of<
|
||||||
|
is_template_base_of<Eigen::EigenBase, T>,
|
||||||
|
negation<any_of<is_eigen_dense_map<T>, is_eigen_dense_plain<T>, is_eigen_sparse<T>>>
|
||||||
|
>;
|
||||||
|
|
||||||
|
// Captures numpy/eigen conformability status (returned by EigenProps::conformable()):
|
||||||
|
template <bool EigenRowMajor> struct EigenConformable {
|
||||||
|
bool conformable = false;
|
||||||
|
EigenIndex rows = 0, cols = 0;
|
||||||
|
EigenDStride stride{0, 0}; // Only valid if negativestrides is false!
|
||||||
|
bool negativestrides = false; // If true, do not use stride!
|
||||||
|
|
||||||
|
EigenConformable(bool fits = false) : conformable{fits} {}
|
||||||
|
// Matrix type:
|
||||||
|
EigenConformable(EigenIndex r, EigenIndex c,
|
||||||
|
EigenIndex rstride, EigenIndex cstride) :
|
||||||
|
conformable{true}, rows{r}, cols{c} {
|
||||||
|
// TODO: when Eigen bug #747 is fixed, remove the tests for non-negativity. http://eigen.tuxfamily.org/bz/show_bug.cgi?id=747
|
||||||
|
if (rstride < 0 || cstride < 0) {
|
||||||
|
negativestrides = true;
|
||||||
|
} else {
|
||||||
|
stride = {EigenRowMajor ? rstride : cstride /* outer stride */,
|
||||||
|
EigenRowMajor ? cstride : rstride /* inner stride */ };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Vector type:
|
||||||
|
EigenConformable(EigenIndex r, EigenIndex c, EigenIndex stride)
|
||||||
|
: EigenConformable(r, c, r == 1 ? c*stride : stride, c == 1 ? r : r*stride) {}
|
||||||
|
|
||||||
|
template <typename props> bool stride_compatible() const {
|
||||||
|
// To have compatible strides, we need (on both dimensions) one of fully dynamic strides,
|
||||||
|
// matching strides, or a dimension size of 1 (in which case the stride value is irrelevant)
|
||||||
|
return
|
||||||
|
!negativestrides &&
|
||||||
|
(props::inner_stride == Eigen::Dynamic || props::inner_stride == stride.inner() ||
|
||||||
|
(EigenRowMajor ? cols : rows) == 1) &&
|
||||||
|
(props::outer_stride == Eigen::Dynamic || props::outer_stride == stride.outer() ||
|
||||||
|
(EigenRowMajor ? rows : cols) == 1);
|
||||||
|
}
|
||||||
|
operator bool() const { return conformable; }
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename Type> struct eigen_extract_stride { using type = Type; };
|
||||||
|
template <typename PlainObjectType, int MapOptions, typename StrideType>
|
||||||
|
struct eigen_extract_stride<Eigen::Map<PlainObjectType, MapOptions, StrideType>> { using type = StrideType; };
|
||||||
|
template <typename PlainObjectType, int Options, typename StrideType>
|
||||||
|
struct eigen_extract_stride<Eigen::Ref<PlainObjectType, Options, StrideType>> { using type = StrideType; };
|
||||||
|
|
||||||
|
// Helper struct for extracting information from an Eigen type
|
||||||
|
template <typename Type_> struct EigenProps {
|
||||||
|
using Type = Type_;
|
||||||
|
using Scalar = typename Type::Scalar;
|
||||||
|
using StrideType = typename eigen_extract_stride<Type>::type;
|
||||||
|
static constexpr EigenIndex
|
||||||
|
rows = Type::RowsAtCompileTime,
|
||||||
|
cols = Type::ColsAtCompileTime,
|
||||||
|
size = Type::SizeAtCompileTime;
|
||||||
|
static constexpr bool
|
||||||
|
row_major = Type::IsRowMajor,
|
||||||
|
vector = Type::IsVectorAtCompileTime, // At least one dimension has fixed size 1
|
||||||
|
fixed_rows = rows != Eigen::Dynamic,
|
||||||
|
fixed_cols = cols != Eigen::Dynamic,
|
||||||
|
fixed = size != Eigen::Dynamic, // Fully-fixed size
|
||||||
|
dynamic = !fixed_rows && !fixed_cols; // Fully-dynamic size
|
||||||
|
|
||||||
|
template <EigenIndex i, EigenIndex ifzero> using if_zero = std::integral_constant<EigenIndex, i == 0 ? ifzero : i>;
|
||||||
|
static constexpr EigenIndex inner_stride = if_zero<StrideType::InnerStrideAtCompileTime, 1>::value,
|
||||||
|
outer_stride = if_zero<StrideType::OuterStrideAtCompileTime,
|
||||||
|
vector ? size : row_major ? cols : rows>::value;
|
||||||
|
static constexpr bool dynamic_stride = inner_stride == Eigen::Dynamic && outer_stride == Eigen::Dynamic;
|
||||||
|
static constexpr bool requires_row_major = !dynamic_stride && !vector && (row_major ? inner_stride : outer_stride) == 1;
|
||||||
|
static constexpr bool requires_col_major = !dynamic_stride && !vector && (row_major ? outer_stride : inner_stride) == 1;
|
||||||
|
|
||||||
|
// Takes an input array and determines whether we can make it fit into the Eigen type. If
|
||||||
|
// the array is a vector, we attempt to fit it into either an Eigen 1xN or Nx1 vector
|
||||||
|
// (preferring the latter if it will fit in either, i.e. for a fully dynamic matrix type).
|
||||||
|
static EigenConformable<row_major> conformable(const array &a) {
|
||||||
|
const auto dims = a.ndim();
|
||||||
|
if (dims < 1 || dims > 2)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (dims == 2) { // Matrix type: require exact match (or dynamic)
|
||||||
|
|
||||||
|
EigenIndex
|
||||||
|
np_rows = a.shape(0),
|
||||||
|
np_cols = a.shape(1),
|
||||||
|
np_rstride = a.strides(0) / static_cast<ssize_t>(sizeof(Scalar)),
|
||||||
|
np_cstride = a.strides(1) / static_cast<ssize_t>(sizeof(Scalar));
|
||||||
|
if ((fixed_rows && np_rows != rows) || (fixed_cols && np_cols != cols))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return {np_rows, np_cols, np_rstride, np_cstride};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Otherwise we're storing an n-vector. Only one of the strides will be used, but whichever
|
||||||
|
// is used, we want the (single) numpy stride value.
|
||||||
|
const EigenIndex n = a.shape(0),
|
||||||
|
stride = a.strides(0) / static_cast<ssize_t>(sizeof(Scalar));
|
||||||
|
|
||||||
|
if (vector) { // Eigen type is a compile-time vector
|
||||||
|
if (fixed && size != n)
|
||||||
|
return false; // Vector size mismatch
|
||||||
|
return {rows == 1 ? 1 : n, cols == 1 ? 1 : n, stride};
|
||||||
|
}
|
||||||
|
else if (fixed) {
|
||||||
|
// The type has a fixed size, but is not a vector: abort
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else if (fixed_cols) {
|
||||||
|
// Since this isn't a vector, cols must be != 1. We allow this only if it exactly
|
||||||
|
// equals the number of elements (rows is Dynamic, and so 1 row is allowed).
|
||||||
|
if (cols != n) return false;
|
||||||
|
return {1, n, stride};
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// Otherwise it's either fully dynamic, or column dynamic; both become a column vector
|
||||||
|
if (fixed_rows && rows != n) return false;
|
||||||
|
return {n, 1, stride};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static constexpr bool show_writeable = is_eigen_dense_map<Type>::value && is_eigen_mutable_map<Type>::value;
|
||||||
|
static constexpr bool show_order = is_eigen_dense_map<Type>::value;
|
||||||
|
static constexpr bool show_c_contiguous = show_order && requires_row_major;
|
||||||
|
static constexpr bool show_f_contiguous = !show_c_contiguous && show_order && requires_col_major;
|
||||||
|
|
||||||
|
static constexpr auto descriptor =
|
||||||
|
_("numpy.ndarray[") + npy_format_descriptor<Scalar>::name +
|
||||||
|
_("[") + _<fixed_rows>(_<(size_t) rows>(), _("m")) +
|
||||||
|
_(", ") + _<fixed_cols>(_<(size_t) cols>(), _("n")) +
|
||||||
|
_("]") +
|
||||||
|
// For a reference type (e.g. Ref<MatrixXd>) we have other constraints that might need to be
|
||||||
|
// satisfied: writeable=True (for a mutable reference), and, depending on the map's stride
|
||||||
|
// options, possibly f_contiguous or c_contiguous. We include them in the descriptor output
|
||||||
|
// to provide some hint as to why a TypeError is occurring (otherwise it can be confusing to
|
||||||
|
// see that a function accepts a 'numpy.ndarray[float64[3,2]]' and an error message that you
|
||||||
|
// *gave* a numpy.ndarray of the right type and dimensions.
|
||||||
|
_<show_writeable>(", flags.writeable", "") +
|
||||||
|
_<show_c_contiguous>(", flags.c_contiguous", "") +
|
||||||
|
_<show_f_contiguous>(", flags.f_contiguous", "") +
|
||||||
|
_("]");
|
||||||
|
};
|
||||||
|
|
||||||
|
// Casts an Eigen type to numpy array. If given a base, the numpy array references the src data,
|
||||||
|
// otherwise it'll make a copy. writeable lets you turn off the writeable flag for the array.
|
||||||
|
template <typename props> handle eigen_array_cast(typename props::Type const &src, handle base = handle(), bool writeable = true) {
|
||||||
|
constexpr ssize_t elem_size = sizeof(typename props::Scalar);
|
||||||
|
array a;
|
||||||
|
if (props::vector)
|
||||||
|
a = array({ src.size() }, { elem_size * src.innerStride() }, src.data(), base);
|
||||||
|
else
|
||||||
|
a = array({ src.rows(), src.cols() }, { elem_size * src.rowStride(), elem_size * src.colStride() },
|
||||||
|
src.data(), base);
|
||||||
|
|
||||||
|
if (!writeable)
|
||||||
|
array_proxy(a.ptr())->flags &= ~detail::npy_api::NPY_ARRAY_WRITEABLE_;
|
||||||
|
|
||||||
|
return a.release();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Takes an lvalue ref to some Eigen type and a (python) base object, creating a numpy array that
|
||||||
|
// reference the Eigen object's data with `base` as the python-registered base class (if omitted,
|
||||||
|
// the base will be set to None, and lifetime management is up to the caller). The numpy array is
|
||||||
|
// non-writeable if the given type is const.
|
||||||
|
template <typename props, typename Type>
|
||||||
|
handle eigen_ref_array(Type &src, handle parent = none()) {
|
||||||
|
// none here is to get past array's should-we-copy detection, which currently always
|
||||||
|
// copies when there is no base. Setting the base to None should be harmless.
|
||||||
|
return eigen_array_cast<props>(src, parent, !std::is_const<Type>::value);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Takes a pointer to some dense, plain Eigen type, builds a capsule around it, then returns a numpy
|
||||||
|
// array that references the encapsulated data with a python-side reference to the capsule to tie
|
||||||
|
// its destruction to that of any dependent python objects. Const-ness is determined by whether or
|
||||||
|
// not the Type of the pointer given is const.
|
||||||
|
template <typename props, typename Type, typename = enable_if_t<is_eigen_dense_plain<Type>::value>>
|
||||||
|
handle eigen_encapsulate(Type *src) {
|
||||||
|
capsule base(src, [](void *o) { delete static_cast<Type *>(o); });
|
||||||
|
return eigen_ref_array<props>(*src, base);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Type caster for regular, dense matrix types (e.g. MatrixXd), but not maps/refs/etc. of dense
|
||||||
|
// types.
|
||||||
|
template<typename Type>
|
||||||
|
struct type_caster<Type, enable_if_t<is_eigen_dense_plain<Type>::value>> {
|
||||||
|
using Scalar = typename Type::Scalar;
|
||||||
|
using props = EigenProps<Type>;
|
||||||
|
|
||||||
|
bool load(handle src, bool convert) {
|
||||||
|
// If we're in no-convert mode, only load if given an array of the correct type
|
||||||
|
if (!convert && !isinstance<array_t<Scalar>>(src))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Coerce into an array, but don't do type conversion yet; the copy below handles it.
|
||||||
|
auto buf = array::ensure(src);
|
||||||
|
|
||||||
|
if (!buf)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
auto dims = buf.ndim();
|
||||||
|
if (dims < 1 || dims > 2)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
auto fits = props::conformable(buf);
|
||||||
|
if (!fits)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Allocate the new type, then build a numpy reference into it
|
||||||
|
value = Type(fits.rows, fits.cols);
|
||||||
|
auto ref = reinterpret_steal<array>(eigen_ref_array<props>(value));
|
||||||
|
if (dims == 1) ref = ref.squeeze();
|
||||||
|
else if (ref.ndim() == 1) buf = buf.squeeze();
|
||||||
|
|
||||||
|
int result = detail::npy_api::get().PyArray_CopyInto_(ref.ptr(), buf.ptr());
|
||||||
|
|
||||||
|
if (result < 0) { // Copy failed!
|
||||||
|
PyErr_Clear();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
// Cast implementation
|
||||||
|
template <typename CType>
|
||||||
|
static handle cast_impl(CType *src, return_value_policy policy, handle parent) {
|
||||||
|
switch (policy) {
|
||||||
|
case return_value_policy::take_ownership:
|
||||||
|
case return_value_policy::automatic:
|
||||||
|
return eigen_encapsulate<props>(src);
|
||||||
|
case return_value_policy::move:
|
||||||
|
return eigen_encapsulate<props>(new CType(std::move(*src)));
|
||||||
|
case return_value_policy::copy:
|
||||||
|
return eigen_array_cast<props>(*src);
|
||||||
|
case return_value_policy::reference:
|
||||||
|
case return_value_policy::automatic_reference:
|
||||||
|
return eigen_ref_array<props>(*src);
|
||||||
|
case return_value_policy::reference_internal:
|
||||||
|
return eigen_ref_array<props>(*src, parent);
|
||||||
|
default:
|
||||||
|
throw cast_error("unhandled return_value_policy: should not happen!");
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
// Normal returned non-reference, non-const value:
|
||||||
|
static handle cast(Type &&src, return_value_policy /* policy */, handle parent) {
|
||||||
|
return cast_impl(&src, return_value_policy::move, parent);
|
||||||
|
}
|
||||||
|
// If you return a non-reference const, we mark the numpy array readonly:
|
||||||
|
static handle cast(const Type &&src, return_value_policy /* policy */, handle parent) {
|
||||||
|
return cast_impl(&src, return_value_policy::move, parent);
|
||||||
|
}
|
||||||
|
// lvalue reference return; default (automatic) becomes copy
|
||||||
|
static handle cast(Type &src, return_value_policy policy, handle parent) {
|
||||||
|
if (policy == return_value_policy::automatic || policy == return_value_policy::automatic_reference)
|
||||||
|
policy = return_value_policy::copy;
|
||||||
|
return cast_impl(&src, policy, parent);
|
||||||
|
}
|
||||||
|
// const lvalue reference return; default (automatic) becomes copy
|
||||||
|
static handle cast(const Type &src, return_value_policy policy, handle parent) {
|
||||||
|
if (policy == return_value_policy::automatic || policy == return_value_policy::automatic_reference)
|
||||||
|
policy = return_value_policy::copy;
|
||||||
|
return cast(&src, policy, parent);
|
||||||
|
}
|
||||||
|
// non-const pointer return
|
||||||
|
static handle cast(Type *src, return_value_policy policy, handle parent) {
|
||||||
|
return cast_impl(src, policy, parent);
|
||||||
|
}
|
||||||
|
// const pointer return
|
||||||
|
static handle cast(const Type *src, return_value_policy policy, handle parent) {
|
||||||
|
return cast_impl(src, policy, parent);
|
||||||
|
}
|
||||||
|
|
||||||
|
static constexpr auto name = props::descriptor;
|
||||||
|
|
||||||
|
operator Type*() { return &value; }
|
||||||
|
operator Type&() { return value; }
|
||||||
|
operator Type&&() && { return std::move(value); }
|
||||||
|
template <typename T> using cast_op_type = movable_cast_op_type<T>;
|
||||||
|
|
||||||
|
private:
|
||||||
|
Type value;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Base class for casting reference/map/block/etc. objects back to python.
|
||||||
|
template <typename MapType> struct eigen_map_caster {
|
||||||
|
private:
|
||||||
|
using props = EigenProps<MapType>;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
// Directly referencing a ref/map's data is a bit dangerous (whatever the map/ref points to has
|
||||||
|
// to stay around), but we'll allow it under the assumption that you know what you're doing (and
|
||||||
|
// have an appropriate keep_alive in place). We return a numpy array pointing directly at the
|
||||||
|
// ref's data (The numpy array ends up read-only if the ref was to a const matrix type.) Note
|
||||||
|
// that this means you need to ensure you don't destroy the object in some other way (e.g. with
|
||||||
|
// an appropriate keep_alive, or with a reference to a statically allocated matrix).
|
||||||
|
static handle cast(const MapType &src, return_value_policy policy, handle parent) {
|
||||||
|
switch (policy) {
|
||||||
|
case return_value_policy::copy:
|
||||||
|
return eigen_array_cast<props>(src);
|
||||||
|
case return_value_policy::reference_internal:
|
||||||
|
return eigen_array_cast<props>(src, parent, is_eigen_mutable_map<MapType>::value);
|
||||||
|
case return_value_policy::reference:
|
||||||
|
case return_value_policy::automatic:
|
||||||
|
case return_value_policy::automatic_reference:
|
||||||
|
return eigen_array_cast<props>(src, none(), is_eigen_mutable_map<MapType>::value);
|
||||||
|
default:
|
||||||
|
// move, take_ownership don't make any sense for a ref/map:
|
||||||
|
pybind11_fail("Invalid return_value_policy for Eigen Map/Ref/Block type");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static constexpr auto name = props::descriptor;
|
||||||
|
|
||||||
|
// Explicitly delete these: support python -> C++ conversion on these (i.e. these can be return
|
||||||
|
// types but not bound arguments). We still provide them (with an explicitly delete) so that
|
||||||
|
// you end up here if you try anyway.
|
||||||
|
bool load(handle, bool) = delete;
|
||||||
|
operator MapType() = delete;
|
||||||
|
template <typename> using cast_op_type = MapType;
|
||||||
|
};
|
||||||
|
|
||||||
|
// We can return any map-like object (but can only load Refs, specialized next):
|
||||||
|
template <typename Type> struct type_caster<Type, enable_if_t<is_eigen_dense_map<Type>::value>>
|
||||||
|
: eigen_map_caster<Type> {};
|
||||||
|
|
||||||
|
// Loader for Ref<...> arguments. See the documentation for info on how to make this work without
|
||||||
|
// copying (it requires some extra effort in many cases).
|
||||||
|
template <typename PlainObjectType, typename StrideType>
|
||||||
|
struct type_caster<
|
||||||
|
Eigen::Ref<PlainObjectType, 0, StrideType>,
|
||||||
|
enable_if_t<is_eigen_dense_map<Eigen::Ref<PlainObjectType, 0, StrideType>>::value>
|
||||||
|
> : public eigen_map_caster<Eigen::Ref<PlainObjectType, 0, StrideType>> {
|
||||||
|
private:
|
||||||
|
using Type = Eigen::Ref<PlainObjectType, 0, StrideType>;
|
||||||
|
using props = EigenProps<Type>;
|
||||||
|
using Scalar = typename props::Scalar;
|
||||||
|
using MapType = Eigen::Map<PlainObjectType, 0, StrideType>;
|
||||||
|
using Array = array_t<Scalar, array::forcecast |
|
||||||
|
((props::row_major ? props::inner_stride : props::outer_stride) == 1 ? array::c_style :
|
||||||
|
(props::row_major ? props::outer_stride : props::inner_stride) == 1 ? array::f_style : 0)>;
|
||||||
|
static constexpr bool need_writeable = is_eigen_mutable_map<Type>::value;
|
||||||
|
// Delay construction (these have no default constructor)
|
||||||
|
std::unique_ptr<MapType> map;
|
||||||
|
std::unique_ptr<Type> ref;
|
||||||
|
// Our array. When possible, this is just a numpy array pointing to the source data, but
|
||||||
|
// sometimes we can't avoid copying (e.g. input is not a numpy array at all, has an incompatible
|
||||||
|
// layout, or is an array of a type that needs to be converted). Using a numpy temporary
|
||||||
|
// (rather than an Eigen temporary) saves an extra copy when we need both type conversion and
|
||||||
|
// storage order conversion. (Note that we refuse to use this temporary copy when loading an
|
||||||
|
// argument for a Ref<M> with M non-const, i.e. a read-write reference).
|
||||||
|
Array copy_or_ref;
|
||||||
|
public:
|
||||||
|
bool load(handle src, bool convert) {
|
||||||
|
// First check whether what we have is already an array of the right type. If not, we can't
|
||||||
|
// avoid a copy (because the copy is also going to do type conversion).
|
||||||
|
bool need_copy = !isinstance<Array>(src);
|
||||||
|
|
||||||
|
EigenConformable<props::row_major> fits;
|
||||||
|
if (!need_copy) {
|
||||||
|
// We don't need a converting copy, but we also need to check whether the strides are
|
||||||
|
// compatible with the Ref's stride requirements
|
||||||
|
Array aref = reinterpret_borrow<Array>(src);
|
||||||
|
|
||||||
|
if (aref && (!need_writeable || aref.writeable())) {
|
||||||
|
fits = props::conformable(aref);
|
||||||
|
if (!fits) return false; // Incompatible dimensions
|
||||||
|
if (!fits.template stride_compatible<props>())
|
||||||
|
need_copy = true;
|
||||||
|
else
|
||||||
|
copy_or_ref = std::move(aref);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
need_copy = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (need_copy) {
|
||||||
|
// We need to copy: If we need a mutable reference, or we're not supposed to convert
|
||||||
|
// (either because we're in the no-convert overload pass, or because we're explicitly
|
||||||
|
// instructed not to copy (via `py::arg().noconvert()`) we have to fail loading.
|
||||||
|
if (!convert || need_writeable) return false;
|
||||||
|
|
||||||
|
Array copy = Array::ensure(src);
|
||||||
|
if (!copy) return false;
|
||||||
|
fits = props::conformable(copy);
|
||||||
|
if (!fits || !fits.template stride_compatible<props>())
|
||||||
|
return false;
|
||||||
|
copy_or_ref = std::move(copy);
|
||||||
|
loader_life_support::add_patient(copy_or_ref);
|
||||||
|
}
|
||||||
|
|
||||||
|
ref.reset();
|
||||||
|
map.reset(new MapType(data(copy_or_ref), fits.rows, fits.cols, make_stride(fits.stride.outer(), fits.stride.inner())));
|
||||||
|
ref.reset(new Type(*map));
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
operator Type*() { return ref.get(); }
|
||||||
|
operator Type&() { return *ref; }
|
||||||
|
template <typename _T> using cast_op_type = pybind11::detail::cast_op_type<_T>;
|
||||||
|
|
||||||
|
private:
|
||||||
|
template <typename T = Type, enable_if_t<is_eigen_mutable_map<T>::value, int> = 0>
|
||||||
|
Scalar *data(Array &a) { return a.mutable_data(); }
|
||||||
|
|
||||||
|
template <typename T = Type, enable_if_t<!is_eigen_mutable_map<T>::value, int> = 0>
|
||||||
|
const Scalar *data(Array &a) { return a.data(); }
|
||||||
|
|
||||||
|
// Attempt to figure out a constructor of `Stride` that will work.
|
||||||
|
// If both strides are fixed, use a default constructor:
|
||||||
|
template <typename S> using stride_ctor_default = bool_constant<
|
||||||
|
S::InnerStrideAtCompileTime != Eigen::Dynamic && S::OuterStrideAtCompileTime != Eigen::Dynamic &&
|
||||||
|
std::is_default_constructible<S>::value>;
|
||||||
|
// Otherwise, if there is a two-index constructor, assume it is (outer,inner) like
|
||||||
|
// Eigen::Stride, and use it:
|
||||||
|
template <typename S> using stride_ctor_dual = bool_constant<
|
||||||
|
!stride_ctor_default<S>::value && std::is_constructible<S, EigenIndex, EigenIndex>::value>;
|
||||||
|
// Otherwise, if there is a one-index constructor, and just one of the strides is dynamic, use
|
||||||
|
// it (passing whichever stride is dynamic).
|
||||||
|
template <typename S> using stride_ctor_outer = bool_constant<
|
||||||
|
!any_of<stride_ctor_default<S>, stride_ctor_dual<S>>::value &&
|
||||||
|
S::OuterStrideAtCompileTime == Eigen::Dynamic && S::InnerStrideAtCompileTime != Eigen::Dynamic &&
|
||||||
|
std::is_constructible<S, EigenIndex>::value>;
|
||||||
|
template <typename S> using stride_ctor_inner = bool_constant<
|
||||||
|
!any_of<stride_ctor_default<S>, stride_ctor_dual<S>>::value &&
|
||||||
|
S::InnerStrideAtCompileTime == Eigen::Dynamic && S::OuterStrideAtCompileTime != Eigen::Dynamic &&
|
||||||
|
std::is_constructible<S, EigenIndex>::value>;
|
||||||
|
|
||||||
|
template <typename S = StrideType, enable_if_t<stride_ctor_default<S>::value, int> = 0>
|
||||||
|
static S make_stride(EigenIndex, EigenIndex) { return S(); }
|
||||||
|
template <typename S = StrideType, enable_if_t<stride_ctor_dual<S>::value, int> = 0>
|
||||||
|
static S make_stride(EigenIndex outer, EigenIndex inner) { return S(outer, inner); }
|
||||||
|
template <typename S = StrideType, enable_if_t<stride_ctor_outer<S>::value, int> = 0>
|
||||||
|
static S make_stride(EigenIndex outer, EigenIndex) { return S(outer); }
|
||||||
|
template <typename S = StrideType, enable_if_t<stride_ctor_inner<S>::value, int> = 0>
|
||||||
|
static S make_stride(EigenIndex, EigenIndex inner) { return S(inner); }
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
// type_caster for special matrix types (e.g. DiagonalMatrix), which are EigenBase, but not
|
||||||
|
// EigenDense (i.e. they don't have a data(), at least not with the usual matrix layout).
|
||||||
|
// load() is not supported, but we can cast them into the python domain by first copying to a
|
||||||
|
// regular Eigen::Matrix, then casting that.
|
||||||
|
template <typename Type>
|
||||||
|
struct type_caster<Type, enable_if_t<is_eigen_other<Type>::value>> {
|
||||||
|
protected:
|
||||||
|
using Matrix = Eigen::Matrix<typename Type::Scalar, Type::RowsAtCompileTime, Type::ColsAtCompileTime>;
|
||||||
|
using props = EigenProps<Matrix>;
|
||||||
|
public:
|
||||||
|
static handle cast(const Type &src, return_value_policy /* policy */, handle /* parent */) {
|
||||||
|
handle h = eigen_encapsulate<props>(new Matrix(src));
|
||||||
|
return h;
|
||||||
|
}
|
||||||
|
static handle cast(const Type *src, return_value_policy policy, handle parent) { return cast(*src, policy, parent); }
|
||||||
|
|
||||||
|
static constexpr auto name = props::descriptor;
|
||||||
|
|
||||||
|
// Explicitly delete these: support python -> C++ conversion on these (i.e. these can be return
|
||||||
|
// types but not bound arguments). We still provide them (with an explicitly delete) so that
|
||||||
|
// you end up here if you try anyway.
|
||||||
|
bool load(handle, bool) = delete;
|
||||||
|
operator Type() = delete;
|
||||||
|
template <typename> using cast_op_type = Type;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename Type>
|
||||||
|
struct type_caster<Type, enable_if_t<is_eigen_sparse<Type>::value>> {
|
||||||
|
typedef typename Type::Scalar Scalar;
|
||||||
|
typedef remove_reference_t<decltype(*std::declval<Type>().outerIndexPtr())> StorageIndex;
|
||||||
|
typedef typename Type::Index Index;
|
||||||
|
static constexpr bool rowMajor = Type::IsRowMajor;
|
||||||
|
|
||||||
|
bool load(handle src, bool) {
|
||||||
|
if (!src)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
auto obj = reinterpret_borrow<object>(src);
|
||||||
|
object sparse_module = module::import("scipy.sparse");
|
||||||
|
object matrix_type = sparse_module.attr(
|
||||||
|
rowMajor ? "csr_matrix" : "csc_matrix");
|
||||||
|
|
||||||
|
if (!obj.get_type().is(matrix_type)) {
|
||||||
|
try {
|
||||||
|
obj = matrix_type(obj);
|
||||||
|
} catch (const error_already_set &) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
auto values = array_t<Scalar>((object) obj.attr("data"));
|
||||||
|
auto innerIndices = array_t<StorageIndex>((object) obj.attr("indices"));
|
||||||
|
auto outerIndices = array_t<StorageIndex>((object) obj.attr("indptr"));
|
||||||
|
auto shape = pybind11::tuple((pybind11::object) obj.attr("shape"));
|
||||||
|
auto nnz = obj.attr("nnz").cast<Index>();
|
||||||
|
|
||||||
|
if (!values || !innerIndices || !outerIndices)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
value = Eigen::MappedSparseMatrix<Scalar, Type::Flags, StorageIndex>(
|
||||||
|
shape[0].cast<Index>(), shape[1].cast<Index>(), nnz,
|
||||||
|
outerIndices.mutable_data(), innerIndices.mutable_data(), values.mutable_data());
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static handle cast(const Type &src, return_value_policy /* policy */, handle /* parent */) {
|
||||||
|
const_cast<Type&>(src).makeCompressed();
|
||||||
|
|
||||||
|
object matrix_type = module::import("scipy.sparse").attr(
|
||||||
|
rowMajor ? "csr_matrix" : "csc_matrix");
|
||||||
|
|
||||||
|
array data(src.nonZeros(), src.valuePtr());
|
||||||
|
array outerIndices((rowMajor ? src.rows() : src.cols()) + 1, src.outerIndexPtr());
|
||||||
|
array innerIndices(src.nonZeros(), src.innerIndexPtr());
|
||||||
|
|
||||||
|
return matrix_type(
|
||||||
|
std::make_tuple(data, innerIndices, outerIndices),
|
||||||
|
std::make_pair(src.rows(), src.cols())
|
||||||
|
).release();
|
||||||
|
}
|
||||||
|
|
||||||
|
PYBIND11_TYPE_CASTER(Type, _<(Type::IsRowMajor) != 0>("scipy.sparse.csr_matrix[", "scipy.sparse.csc_matrix[")
|
||||||
|
+ npy_format_descriptor<Scalar>::name + _("]"));
|
||||||
|
};
|
||||||
|
|
||||||
|
NAMESPACE_END(detail)
|
||||||
|
NAMESPACE_END(PYBIND11_NAMESPACE)
|
||||||
|
|
||||||
|
#if defined(__GNUG__) || defined(__clang__)
|
||||||
|
# pragma GCC diagnostic pop
|
||||||
|
#elif defined(_MSC_VER)
|
||||||
|
# pragma warning(pop)
|
||||||
|
#endif
|
202
3rdparty/pybind11/include/pybind11/embed.h
vendored
Normal file
202
3rdparty/pybind11/include/pybind11/embed.h
vendored
Normal file
@ -0,0 +1,202 @@
|
|||||||
|
/*
|
||||||
|
pybind11/embed.h: Support for embedding the interpreter
|
||||||
|
|
||||||
|
Copyright (c) 2017 Wenzel Jakob <wenzel.jakob@epfl.ch>
|
||||||
|
|
||||||
|
All rights reserved. Use of this source code is governed by a
|
||||||
|
BSD-style license that can be found in the LICENSE file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "pybind11.h"
|
||||||
|
#include "eval.h"
|
||||||
|
|
||||||
|
#if defined(PYPY_VERSION)
|
||||||
|
# error Embedding the interpreter is not supported with PyPy
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if PY_MAJOR_VERSION >= 3
|
||||||
|
# define PYBIND11_EMBEDDED_MODULE_IMPL(name) \
|
||||||
|
extern "C" PyObject *pybind11_init_impl_##name(); \
|
||||||
|
extern "C" PyObject *pybind11_init_impl_##name() { \
|
||||||
|
return pybind11_init_wrapper_##name(); \
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
# define PYBIND11_EMBEDDED_MODULE_IMPL(name) \
|
||||||
|
extern "C" void pybind11_init_impl_##name(); \
|
||||||
|
extern "C" void pybind11_init_impl_##name() { \
|
||||||
|
pybind11_init_wrapper_##name(); \
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/** \rst
|
||||||
|
Add a new module to the table of builtins for the interpreter. Must be
|
||||||
|
defined in global scope. The first macro parameter is the name of the
|
||||||
|
module (without quotes). The second parameter is the variable which will
|
||||||
|
be used as the interface to add functions and classes to the module.
|
||||||
|
|
||||||
|
.. code-block:: cpp
|
||||||
|
|
||||||
|
PYBIND11_EMBEDDED_MODULE(example, m) {
|
||||||
|
// ... initialize functions and classes here
|
||||||
|
m.def("foo", []() {
|
||||||
|
return "Hello, World!";
|
||||||
|
});
|
||||||
|
}
|
||||||
|
\endrst */
|
||||||
|
#define PYBIND11_EMBEDDED_MODULE(name, variable) \
|
||||||
|
static void PYBIND11_CONCAT(pybind11_init_, name)(pybind11::module &); \
|
||||||
|
static PyObject PYBIND11_CONCAT(*pybind11_init_wrapper_, name)() { \
|
||||||
|
auto m = pybind11::module(PYBIND11_TOSTRING(name)); \
|
||||||
|
try { \
|
||||||
|
PYBIND11_CONCAT(pybind11_init_, name)(m); \
|
||||||
|
return m.ptr(); \
|
||||||
|
} catch (pybind11::error_already_set &e) { \
|
||||||
|
PyErr_SetString(PyExc_ImportError, e.what()); \
|
||||||
|
return nullptr; \
|
||||||
|
} catch (const std::exception &e) { \
|
||||||
|
PyErr_SetString(PyExc_ImportError, e.what()); \
|
||||||
|
return nullptr; \
|
||||||
|
} \
|
||||||
|
} \
|
||||||
|
PYBIND11_EMBEDDED_MODULE_IMPL(name) \
|
||||||
|
pybind11::detail::embedded_module name(PYBIND11_TOSTRING(name), \
|
||||||
|
PYBIND11_CONCAT(pybind11_init_impl_, name)); \
|
||||||
|
void PYBIND11_CONCAT(pybind11_init_, name)(pybind11::module &variable)
|
||||||
|
|
||||||
|
|
||||||
|
NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
|
||||||
|
NAMESPACE_BEGIN(detail)
|
||||||
|
|
||||||
|
/// Python 2.7/3.x compatible version of `PyImport_AppendInittab` and error checks.
|
||||||
|
struct embedded_module {
|
||||||
|
#if PY_MAJOR_VERSION >= 3
|
||||||
|
using init_t = PyObject *(*)();
|
||||||
|
#else
|
||||||
|
using init_t = void (*)();
|
||||||
|
#endif
|
||||||
|
embedded_module(const char *name, init_t init) {
|
||||||
|
if (Py_IsInitialized())
|
||||||
|
pybind11_fail("Can't add new modules after the interpreter has been initialized");
|
||||||
|
|
||||||
|
auto result = PyImport_AppendInittab(name, init);
|
||||||
|
if (result == -1)
|
||||||
|
pybind11_fail("Insufficient memory to add a new module");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
NAMESPACE_END(detail)
|
||||||
|
|
||||||
|
/** \rst
|
||||||
|
Initialize the Python interpreter. No other pybind11 or CPython API functions can be
|
||||||
|
called before this is done; with the exception of `PYBIND11_EMBEDDED_MODULE`. The
|
||||||
|
optional parameter can be used to skip the registration of signal handlers (see the
|
||||||
|
`Python documentation`_ for details). Calling this function again after the interpreter
|
||||||
|
has already been initialized is a fatal error.
|
||||||
|
|
||||||
|
If initializing the Python interpreter fails, then the program is terminated. (This
|
||||||
|
is controlled by the CPython runtime and is an exception to pybind11's normal behavior
|
||||||
|
of throwing exceptions on errors.)
|
||||||
|
|
||||||
|
.. _Python documentation: https://docs.python.org/3/c-api/init.html#c.Py_InitializeEx
|
||||||
|
\endrst */
|
||||||
|
inline void initialize_interpreter(bool init_signal_handlers = true) {
|
||||||
|
if (Py_IsInitialized())
|
||||||
|
pybind11_fail("The interpreter is already running");
|
||||||
|
|
||||||
|
Py_InitializeEx(init_signal_handlers ? 1 : 0);
|
||||||
|
|
||||||
|
// Make .py files in the working directory available by default
|
||||||
|
module::import("sys").attr("path").cast<list>().append(".");
|
||||||
|
}
|
||||||
|
|
||||||
|
/** \rst
|
||||||
|
Shut down the Python interpreter. No pybind11 or CPython API functions can be called
|
||||||
|
after this. In addition, pybind11 objects must not outlive the interpreter:
|
||||||
|
|
||||||
|
.. code-block:: cpp
|
||||||
|
|
||||||
|
{ // BAD
|
||||||
|
py::initialize_interpreter();
|
||||||
|
auto hello = py::str("Hello, World!");
|
||||||
|
py::finalize_interpreter();
|
||||||
|
} // <-- BOOM, hello's destructor is called after interpreter shutdown
|
||||||
|
|
||||||
|
{ // GOOD
|
||||||
|
py::initialize_interpreter();
|
||||||
|
{ // scoped
|
||||||
|
auto hello = py::str("Hello, World!");
|
||||||
|
} // <-- OK, hello is cleaned up properly
|
||||||
|
py::finalize_interpreter();
|
||||||
|
}
|
||||||
|
|
||||||
|
{ // BETTER
|
||||||
|
py::scoped_interpreter guard{};
|
||||||
|
auto hello = py::str("Hello, World!");
|
||||||
|
}
|
||||||
|
|
||||||
|
.. warning::
|
||||||
|
|
||||||
|
The interpreter can be restarted by calling `initialize_interpreter` again.
|
||||||
|
Modules created using pybind11 can be safely re-initialized. However, Python
|
||||||
|
itself cannot completely unload binary extension modules and there are several
|
||||||
|
caveats with regard to interpreter restarting. All the details can be found
|
||||||
|
in the CPython documentation. In short, not all interpreter memory may be
|
||||||
|
freed, either due to reference cycles or user-created global data.
|
||||||
|
|
||||||
|
\endrst */
|
||||||
|
inline void finalize_interpreter() {
|
||||||
|
handle builtins(PyEval_GetBuiltins());
|
||||||
|
const char *id = PYBIND11_INTERNALS_ID;
|
||||||
|
|
||||||
|
// Get the internals pointer (without creating it if it doesn't exist). It's possible for the
|
||||||
|
// internals to be created during Py_Finalize() (e.g. if a py::capsule calls `get_internals()`
|
||||||
|
// during destruction), so we get the pointer-pointer here and check it after Py_Finalize().
|
||||||
|
detail::internals **internals_ptr_ptr = detail::get_internals_pp();
|
||||||
|
// It could also be stashed in builtins, so look there too:
|
||||||
|
if (builtins.contains(id) && isinstance<capsule>(builtins[id]))
|
||||||
|
internals_ptr_ptr = capsule(builtins[id]);
|
||||||
|
|
||||||
|
Py_Finalize();
|
||||||
|
|
||||||
|
if (internals_ptr_ptr) {
|
||||||
|
delete *internals_ptr_ptr;
|
||||||
|
*internals_ptr_ptr = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** \rst
|
||||||
|
Scope guard version of `initialize_interpreter` and `finalize_interpreter`.
|
||||||
|
This a move-only guard and only a single instance can exist.
|
||||||
|
|
||||||
|
.. code-block:: cpp
|
||||||
|
|
||||||
|
#include <pybind11/embed.h>
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
py::scoped_interpreter guard{};
|
||||||
|
py::print(Hello, World!);
|
||||||
|
} // <-- interpreter shutdown
|
||||||
|
\endrst */
|
||||||
|
class scoped_interpreter {
|
||||||
|
public:
|
||||||
|
scoped_interpreter(bool init_signal_handlers = true) {
|
||||||
|
initialize_interpreter(init_signal_handlers);
|
||||||
|
}
|
||||||
|
|
||||||
|
scoped_interpreter(const scoped_interpreter &) = delete;
|
||||||
|
scoped_interpreter(scoped_interpreter &&other) noexcept { other.is_valid = false; }
|
||||||
|
scoped_interpreter &operator=(const scoped_interpreter &) = delete;
|
||||||
|
scoped_interpreter &operator=(scoped_interpreter &&) = delete;
|
||||||
|
|
||||||
|
~scoped_interpreter() {
|
||||||
|
if (is_valid)
|
||||||
|
finalize_interpreter();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool is_valid = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
NAMESPACE_END(PYBIND11_NAMESPACE)
|
117
3rdparty/pybind11/include/pybind11/eval.h
vendored
Normal file
117
3rdparty/pybind11/include/pybind11/eval.h
vendored
Normal file
@ -0,0 +1,117 @@
|
|||||||
|
/*
|
||||||
|
pybind11/exec.h: Support for evaluating Python expressions and statements
|
||||||
|
from strings and files
|
||||||
|
|
||||||
|
Copyright (c) 2016 Klemens Morgenstern <klemens.morgenstern@ed-chemnitz.de> and
|
||||||
|
Wenzel Jakob <wenzel.jakob@epfl.ch>
|
||||||
|
|
||||||
|
All rights reserved. Use of this source code is governed by a
|
||||||
|
BSD-style license that can be found in the LICENSE file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "pybind11.h"
|
||||||
|
|
||||||
|
NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
|
||||||
|
|
||||||
|
enum eval_mode {
|
||||||
|
/// Evaluate a string containing an isolated expression
|
||||||
|
eval_expr,
|
||||||
|
|
||||||
|
/// Evaluate a string containing a single statement. Returns \c none
|
||||||
|
eval_single_statement,
|
||||||
|
|
||||||
|
/// Evaluate a string containing a sequence of statement. Returns \c none
|
||||||
|
eval_statements
|
||||||
|
};
|
||||||
|
|
||||||
|
template <eval_mode mode = eval_expr>
|
||||||
|
object eval(str expr, object global = globals(), object local = object()) {
|
||||||
|
if (!local)
|
||||||
|
local = global;
|
||||||
|
|
||||||
|
/* PyRun_String does not accept a PyObject / encoding specifier,
|
||||||
|
this seems to be the only alternative */
|
||||||
|
std::string buffer = "# -*- coding: utf-8 -*-\n" + (std::string) expr;
|
||||||
|
|
||||||
|
int start;
|
||||||
|
switch (mode) {
|
||||||
|
case eval_expr: start = Py_eval_input; break;
|
||||||
|
case eval_single_statement: start = Py_single_input; break;
|
||||||
|
case eval_statements: start = Py_file_input; break;
|
||||||
|
default: pybind11_fail("invalid evaluation mode");
|
||||||
|
}
|
||||||
|
|
||||||
|
PyObject *result = PyRun_String(buffer.c_str(), start, global.ptr(), local.ptr());
|
||||||
|
if (!result)
|
||||||
|
throw error_already_set();
|
||||||
|
return reinterpret_steal<object>(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <eval_mode mode = eval_expr, size_t N>
|
||||||
|
object eval(const char (&s)[N], object global = globals(), object local = object()) {
|
||||||
|
/* Support raw string literals by removing common leading whitespace */
|
||||||
|
auto expr = (s[0] == '\n') ? str(module::import("textwrap").attr("dedent")(s))
|
||||||
|
: str(s);
|
||||||
|
return eval<mode>(expr, global, local);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void exec(str expr, object global = globals(), object local = object()) {
|
||||||
|
eval<eval_statements>(expr, global, local);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <size_t N>
|
||||||
|
void exec(const char (&s)[N], object global = globals(), object local = object()) {
|
||||||
|
eval<eval_statements>(s, global, local);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <eval_mode mode = eval_statements>
|
||||||
|
object eval_file(str fname, object global = globals(), object local = object()) {
|
||||||
|
if (!local)
|
||||||
|
local = global;
|
||||||
|
|
||||||
|
int start;
|
||||||
|
switch (mode) {
|
||||||
|
case eval_expr: start = Py_eval_input; break;
|
||||||
|
case eval_single_statement: start = Py_single_input; break;
|
||||||
|
case eval_statements: start = Py_file_input; break;
|
||||||
|
default: pybind11_fail("invalid evaluation mode");
|
||||||
|
}
|
||||||
|
|
||||||
|
int closeFile = 1;
|
||||||
|
std::string fname_str = (std::string) fname;
|
||||||
|
#if PY_VERSION_HEX >= 0x03040000
|
||||||
|
FILE *f = _Py_fopen_obj(fname.ptr(), "r");
|
||||||
|
#elif PY_VERSION_HEX >= 0x03000000
|
||||||
|
FILE *f = _Py_fopen(fname.ptr(), "r");
|
||||||
|
#else
|
||||||
|
/* No unicode support in open() :( */
|
||||||
|
auto fobj = reinterpret_steal<object>(PyFile_FromString(
|
||||||
|
const_cast<char *>(fname_str.c_str()),
|
||||||
|
const_cast<char*>("r")));
|
||||||
|
FILE *f = nullptr;
|
||||||
|
if (fobj)
|
||||||
|
f = PyFile_AsFile(fobj.ptr());
|
||||||
|
closeFile = 0;
|
||||||
|
#endif
|
||||||
|
if (!f) {
|
||||||
|
PyErr_Clear();
|
||||||
|
pybind11_fail("File \"" + fname_str + "\" could not be opened!");
|
||||||
|
}
|
||||||
|
|
||||||
|
#if PY_VERSION_HEX < 0x03000000 && defined(PYPY_VERSION)
|
||||||
|
PyObject *result = PyRun_File(f, fname_str.c_str(), start, global.ptr(),
|
||||||
|
local.ptr());
|
||||||
|
(void) closeFile;
|
||||||
|
#else
|
||||||
|
PyObject *result = PyRun_FileEx(f, fname_str.c_str(), start, global.ptr(),
|
||||||
|
local.ptr(), closeFile);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (!result)
|
||||||
|
throw error_already_set();
|
||||||
|
return reinterpret_steal<object>(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
NAMESPACE_END(PYBIND11_NAMESPACE)
|
101
3rdparty/pybind11/include/pybind11/functional.h
vendored
Normal file
101
3rdparty/pybind11/include/pybind11/functional.h
vendored
Normal file
@ -0,0 +1,101 @@
|
|||||||
|
/*
|
||||||
|
pybind11/functional.h: std::function<> support
|
||||||
|
|
||||||
|
Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch>
|
||||||
|
|
||||||
|
All rights reserved. Use of this source code is governed by a
|
||||||
|
BSD-style license that can be found in the LICENSE file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "pybind11.h"
|
||||||
|
#include <functional>
|
||||||
|
|
||||||
|
NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
|
||||||
|
NAMESPACE_BEGIN(detail)
|
||||||
|
|
||||||
|
template <typename Return, typename... Args>
|
||||||
|
struct type_caster<std::function<Return(Args...)>> {
|
||||||
|
using type = std::function<Return(Args...)>;
|
||||||
|
using retval_type = conditional_t<std::is_same<Return, void>::value, void_type, Return>;
|
||||||
|
using function_type = Return (*) (Args...);
|
||||||
|
|
||||||
|
public:
|
||||||
|
bool load(handle src, bool convert) {
|
||||||
|
if (src.is_none()) {
|
||||||
|
// Defer accepting None to other overloads (if we aren't in convert mode):
|
||||||
|
if (!convert) return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isinstance<function>(src))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
auto func = reinterpret_borrow<function>(src);
|
||||||
|
|
||||||
|
/*
|
||||||
|
When passing a C++ function as an argument to another C++
|
||||||
|
function via Python, every function call would normally involve
|
||||||
|
a full C++ -> Python -> C++ roundtrip, which can be prohibitive.
|
||||||
|
Here, we try to at least detect the case where the function is
|
||||||
|
stateless (i.e. function pointer or lambda function without
|
||||||
|
captured variables), in which case the roundtrip can be avoided.
|
||||||
|
*/
|
||||||
|
if (auto cfunc = func.cpp_function()) {
|
||||||
|
auto c = reinterpret_borrow<capsule>(PyCFunction_GET_SELF(cfunc.ptr()));
|
||||||
|
auto rec = (function_record *) c;
|
||||||
|
|
||||||
|
if (rec && rec->is_stateless &&
|
||||||
|
same_type(typeid(function_type), *reinterpret_cast<const std::type_info *>(rec->data[1]))) {
|
||||||
|
struct capture { function_type f; };
|
||||||
|
value = ((capture *) &rec->data)->f;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ensure GIL is held during functor destruction
|
||||||
|
struct func_handle {
|
||||||
|
function f;
|
||||||
|
func_handle(function&& f_) : f(std::move(f_)) {}
|
||||||
|
func_handle(const func_handle&) = default;
|
||||||
|
~func_handle() {
|
||||||
|
gil_scoped_acquire acq;
|
||||||
|
function kill_f(std::move(f));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// to emulate 'move initialization capture' in C++11
|
||||||
|
struct func_wrapper {
|
||||||
|
func_handle hfunc;
|
||||||
|
func_wrapper(func_handle&& hf): hfunc(std::move(hf)) {}
|
||||||
|
Return operator()(Args... args) const {
|
||||||
|
gil_scoped_acquire acq;
|
||||||
|
object retval(hfunc.f(std::forward<Args>(args)...));
|
||||||
|
/* Visual studio 2015 parser issue: need parentheses around this expression */
|
||||||
|
return (retval.template cast<Return>());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
value = func_wrapper(func_handle(std::move(func)));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Func>
|
||||||
|
static handle cast(Func &&f_, return_value_policy policy, handle /* parent */) {
|
||||||
|
if (!f_)
|
||||||
|
return none().inc_ref();
|
||||||
|
|
||||||
|
auto result = f_.template target<function_type>();
|
||||||
|
if (result)
|
||||||
|
return cpp_function(*result, policy).release();
|
||||||
|
else
|
||||||
|
return cpp_function(std::forward<Func>(f_), policy).release();
|
||||||
|
}
|
||||||
|
|
||||||
|
PYBIND11_TYPE_CASTER(type, _("Callable[[") + concat(make_caster<Args>::name...) + _("], ")
|
||||||
|
+ make_caster<retval_type>::name + _("]"));
|
||||||
|
};
|
||||||
|
|
||||||
|
NAMESPACE_END(detail)
|
||||||
|
NAMESPACE_END(PYBIND11_NAMESPACE)
|
209
3rdparty/pybind11/include/pybind11/iostream.h
vendored
Normal file
209
3rdparty/pybind11/include/pybind11/iostream.h
vendored
Normal file
@ -0,0 +1,209 @@
|
|||||||
|
/*
|
||||||
|
pybind11/iostream.h -- Tools to assist with redirecting cout and cerr to Python
|
||||||
|
|
||||||
|
Copyright (c) 2017 Henry F. Schreiner
|
||||||
|
|
||||||
|
All rights reserved. Use of this source code is governed by a
|
||||||
|
BSD-style license that can be found in the LICENSE file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "pybind11.h"
|
||||||
|
|
||||||
|
#include <streambuf>
|
||||||
|
#include <ostream>
|
||||||
|
#include <string>
|
||||||
|
#include <memory>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
|
||||||
|
NAMESPACE_BEGIN(detail)
|
||||||
|
|
||||||
|
// Buffer that writes to Python instead of C++
|
||||||
|
class pythonbuf : public std::streambuf {
|
||||||
|
private:
|
||||||
|
using traits_type = std::streambuf::traits_type;
|
||||||
|
|
||||||
|
const size_t buf_size;
|
||||||
|
std::unique_ptr<char[]> d_buffer;
|
||||||
|
object pywrite;
|
||||||
|
object pyflush;
|
||||||
|
|
||||||
|
int overflow(int c) {
|
||||||
|
if (!traits_type::eq_int_type(c, traits_type::eof())) {
|
||||||
|
*pptr() = traits_type::to_char_type(c);
|
||||||
|
pbump(1);
|
||||||
|
}
|
||||||
|
return sync() == 0 ? traits_type::not_eof(c) : traits_type::eof();
|
||||||
|
}
|
||||||
|
|
||||||
|
int sync() {
|
||||||
|
if (pbase() != pptr()) {
|
||||||
|
// This subtraction cannot be negative, so dropping the sign
|
||||||
|
str line(pbase(), static_cast<size_t>(pptr() - pbase()));
|
||||||
|
|
||||||
|
{
|
||||||
|
gil_scoped_acquire tmp;
|
||||||
|
pywrite(line);
|
||||||
|
pyflush();
|
||||||
|
}
|
||||||
|
|
||||||
|
setp(pbase(), epptr());
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
pythonbuf(object pyostream, size_t buffer_size = 1024)
|
||||||
|
: buf_size(buffer_size),
|
||||||
|
d_buffer(new char[buf_size]),
|
||||||
|
pywrite(pyostream.attr("write")),
|
||||||
|
pyflush(pyostream.attr("flush")) {
|
||||||
|
setp(d_buffer.get(), d_buffer.get() + buf_size - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
pythonbuf(pythonbuf&&) = default;
|
||||||
|
|
||||||
|
/// Sync before destroy
|
||||||
|
~pythonbuf() {
|
||||||
|
sync();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
NAMESPACE_END(detail)
|
||||||
|
|
||||||
|
|
||||||
|
/** \rst
|
||||||
|
This a move-only guard that redirects output.
|
||||||
|
|
||||||
|
.. code-block:: cpp
|
||||||
|
|
||||||
|
#include <pybind11/iostream.h>
|
||||||
|
|
||||||
|
...
|
||||||
|
|
||||||
|
{
|
||||||
|
py::scoped_ostream_redirect output;
|
||||||
|
std::cout << "Hello, World!"; // Python stdout
|
||||||
|
} // <-- return std::cout to normal
|
||||||
|
|
||||||
|
You can explicitly pass the c++ stream and the python object,
|
||||||
|
for example to guard stderr instead.
|
||||||
|
|
||||||
|
.. code-block:: cpp
|
||||||
|
|
||||||
|
{
|
||||||
|
py::scoped_ostream_redirect output{std::cerr, py::module::import("sys").attr("stderr")};
|
||||||
|
std::cerr << "Hello, World!";
|
||||||
|
}
|
||||||
|
\endrst */
|
||||||
|
class scoped_ostream_redirect {
|
||||||
|
protected:
|
||||||
|
std::streambuf *old;
|
||||||
|
std::ostream &costream;
|
||||||
|
detail::pythonbuf buffer;
|
||||||
|
|
||||||
|
public:
|
||||||
|
scoped_ostream_redirect(
|
||||||
|
std::ostream &costream = std::cout,
|
||||||
|
object pyostream = module::import("sys").attr("stdout"))
|
||||||
|
: costream(costream), buffer(pyostream) {
|
||||||
|
old = costream.rdbuf(&buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
~scoped_ostream_redirect() {
|
||||||
|
costream.rdbuf(old);
|
||||||
|
}
|
||||||
|
|
||||||
|
scoped_ostream_redirect(const scoped_ostream_redirect &) = delete;
|
||||||
|
scoped_ostream_redirect(scoped_ostream_redirect &&other) = default;
|
||||||
|
scoped_ostream_redirect &operator=(const scoped_ostream_redirect &) = delete;
|
||||||
|
scoped_ostream_redirect &operator=(scoped_ostream_redirect &&) = delete;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/** \rst
|
||||||
|
Like `scoped_ostream_redirect`, but redirects cerr by default. This class
|
||||||
|
is provided primary to make ``py::call_guard`` easier to make.
|
||||||
|
|
||||||
|
.. code-block:: cpp
|
||||||
|
|
||||||
|
m.def("noisy_func", &noisy_func,
|
||||||
|
py::call_guard<scoped_ostream_redirect,
|
||||||
|
scoped_estream_redirect>());
|
||||||
|
|
||||||
|
\endrst */
|
||||||
|
class scoped_estream_redirect : public scoped_ostream_redirect {
|
||||||
|
public:
|
||||||
|
scoped_estream_redirect(
|
||||||
|
std::ostream &costream = std::cerr,
|
||||||
|
object pyostream = module::import("sys").attr("stderr"))
|
||||||
|
: scoped_ostream_redirect(costream,pyostream) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
NAMESPACE_BEGIN(detail)
|
||||||
|
|
||||||
|
// Class to redirect output as a context manager. C++ backend.
|
||||||
|
class OstreamRedirect {
|
||||||
|
bool do_stdout_;
|
||||||
|
bool do_stderr_;
|
||||||
|
std::unique_ptr<scoped_ostream_redirect> redirect_stdout;
|
||||||
|
std::unique_ptr<scoped_estream_redirect> redirect_stderr;
|
||||||
|
|
||||||
|
public:
|
||||||
|
OstreamRedirect(bool do_stdout = true, bool do_stderr = true)
|
||||||
|
: do_stdout_(do_stdout), do_stderr_(do_stderr) {}
|
||||||
|
|
||||||
|
void enter() {
|
||||||
|
if (do_stdout_)
|
||||||
|
redirect_stdout.reset(new scoped_ostream_redirect());
|
||||||
|
if (do_stderr_)
|
||||||
|
redirect_stderr.reset(new scoped_estream_redirect());
|
||||||
|
}
|
||||||
|
|
||||||
|
void exit() {
|
||||||
|
redirect_stdout.reset();
|
||||||
|
redirect_stderr.reset();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
NAMESPACE_END(detail)
|
||||||
|
|
||||||
|
/** \rst
|
||||||
|
This is a helper function to add a C++ redirect context manager to Python
|
||||||
|
instead of using a C++ guard. To use it, add the following to your binding code:
|
||||||
|
|
||||||
|
.. code-block:: cpp
|
||||||
|
|
||||||
|
#include <pybind11/iostream.h>
|
||||||
|
|
||||||
|
...
|
||||||
|
|
||||||
|
py::add_ostream_redirect(m, "ostream_redirect");
|
||||||
|
|
||||||
|
You now have a Python context manager that redirects your output:
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
with m.ostream_redirect():
|
||||||
|
m.print_to_cout_function()
|
||||||
|
|
||||||
|
This manager can optionally be told which streams to operate on:
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
with m.ostream_redirect(stdout=true, stderr=true):
|
||||||
|
m.noisy_function_with_error_printing()
|
||||||
|
|
||||||
|
\endrst */
|
||||||
|
inline class_<detail::OstreamRedirect> add_ostream_redirect(module m, std::string name = "ostream_redirect") {
|
||||||
|
return class_<detail::OstreamRedirect>(m, name.c_str(), module_local())
|
||||||
|
.def(init<bool,bool>(), arg("stdout")=true, arg("stderr")=true)
|
||||||
|
.def("__enter__", &detail::OstreamRedirect::enter)
|
||||||
|
.def("__exit__", [](detail::OstreamRedirect &self_, args) { self_.exit(); });
|
||||||
|
}
|
||||||
|
|
||||||
|
NAMESPACE_END(PYBIND11_NAMESPACE)
|
1642
3rdparty/pybind11/include/pybind11/numpy.h
vendored
Normal file
1642
3rdparty/pybind11/include/pybind11/numpy.h
vendored
Normal file
File diff suppressed because it is too large
Load Diff
168
3rdparty/pybind11/include/pybind11/operators.h
vendored
Normal file
168
3rdparty/pybind11/include/pybind11/operators.h
vendored
Normal file
@ -0,0 +1,168 @@
|
|||||||
|
/*
|
||||||
|
pybind11/operator.h: Metatemplates for operator overloading
|
||||||
|
|
||||||
|
Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch>
|
||||||
|
|
||||||
|
All rights reserved. Use of this source code is governed by a
|
||||||
|
BSD-style license that can be found in the LICENSE file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "pybind11.h"
|
||||||
|
|
||||||
|
#if defined(__clang__) && !defined(__INTEL_COMPILER)
|
||||||
|
# pragma clang diagnostic ignored "-Wunsequenced" // multiple unsequenced modifications to 'self' (when using def(py::self OP Type()))
|
||||||
|
#elif defined(_MSC_VER)
|
||||||
|
# pragma warning(push)
|
||||||
|
# pragma warning(disable: 4127) // warning C4127: Conditional expression is constant
|
||||||
|
#endif
|
||||||
|
|
||||||
|
NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
|
||||||
|
NAMESPACE_BEGIN(detail)
|
||||||
|
|
||||||
|
/// Enumeration with all supported operator types
|
||||||
|
enum op_id : int {
|
||||||
|
op_add, op_sub, op_mul, op_div, op_mod, op_divmod, op_pow, op_lshift,
|
||||||
|
op_rshift, op_and, op_xor, op_or, op_neg, op_pos, op_abs, op_invert,
|
||||||
|
op_int, op_long, op_float, op_str, op_cmp, op_gt, op_ge, op_lt, op_le,
|
||||||
|
op_eq, op_ne, op_iadd, op_isub, op_imul, op_idiv, op_imod, op_ilshift,
|
||||||
|
op_irshift, op_iand, op_ixor, op_ior, op_complex, op_bool, op_nonzero,
|
||||||
|
op_repr, op_truediv, op_itruediv, op_hash
|
||||||
|
};
|
||||||
|
|
||||||
|
enum op_type : int {
|
||||||
|
op_l, /* base type on left */
|
||||||
|
op_r, /* base type on right */
|
||||||
|
op_u /* unary operator */
|
||||||
|
};
|
||||||
|
|
||||||
|
struct self_t { };
|
||||||
|
static const self_t self = self_t();
|
||||||
|
|
||||||
|
/// Type for an unused type slot
|
||||||
|
struct undefined_t { };
|
||||||
|
|
||||||
|
/// Don't warn about an unused variable
|
||||||
|
inline self_t __self() { return self; }
|
||||||
|
|
||||||
|
/// base template of operator implementations
|
||||||
|
template <op_id, op_type, typename B, typename L, typename R> struct op_impl { };
|
||||||
|
|
||||||
|
/// Operator implementation generator
|
||||||
|
template <op_id id, op_type ot, typename L, typename R> struct op_ {
|
||||||
|
template <typename Class, typename... Extra> void execute(Class &cl, const Extra&... extra) const {
|
||||||
|
using Base = typename Class::type;
|
||||||
|
using L_type = conditional_t<std::is_same<L, self_t>::value, Base, L>;
|
||||||
|
using R_type = conditional_t<std::is_same<R, self_t>::value, Base, R>;
|
||||||
|
using op = op_impl<id, ot, Base, L_type, R_type>;
|
||||||
|
cl.def(op::name(), &op::execute, is_operator(), extra...);
|
||||||
|
#if PY_MAJOR_VERSION < 3
|
||||||
|
if (id == op_truediv || id == op_itruediv)
|
||||||
|
cl.def(id == op_itruediv ? "__idiv__" : ot == op_l ? "__div__" : "__rdiv__",
|
||||||
|
&op::execute, is_operator(), extra...);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
template <typename Class, typename... Extra> void execute_cast(Class &cl, const Extra&... extra) const {
|
||||||
|
using Base = typename Class::type;
|
||||||
|
using L_type = conditional_t<std::is_same<L, self_t>::value, Base, L>;
|
||||||
|
using R_type = conditional_t<std::is_same<R, self_t>::value, Base, R>;
|
||||||
|
using op = op_impl<id, ot, Base, L_type, R_type>;
|
||||||
|
cl.def(op::name(), &op::execute_cast, is_operator(), extra...);
|
||||||
|
#if PY_MAJOR_VERSION < 3
|
||||||
|
if (id == op_truediv || id == op_itruediv)
|
||||||
|
cl.def(id == op_itruediv ? "__idiv__" : ot == op_l ? "__div__" : "__rdiv__",
|
||||||
|
&op::execute, is_operator(), extra...);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
#define PYBIND11_BINARY_OPERATOR(id, rid, op, expr) \
|
||||||
|
template <typename B, typename L, typename R> struct op_impl<op_##id, op_l, B, L, R> { \
|
||||||
|
static char const* name() { return "__" #id "__"; } \
|
||||||
|
static auto execute(const L &l, const R &r) -> decltype(expr) { return (expr); } \
|
||||||
|
static B execute_cast(const L &l, const R &r) { return B(expr); } \
|
||||||
|
}; \
|
||||||
|
template <typename B, typename L, typename R> struct op_impl<op_##id, op_r, B, L, R> { \
|
||||||
|
static char const* name() { return "__" #rid "__"; } \
|
||||||
|
static auto execute(const R &r, const L &l) -> decltype(expr) { return (expr); } \
|
||||||
|
static B execute_cast(const R &r, const L &l) { return B(expr); } \
|
||||||
|
}; \
|
||||||
|
inline op_<op_##id, op_l, self_t, self_t> op(const self_t &, const self_t &) { \
|
||||||
|
return op_<op_##id, op_l, self_t, self_t>(); \
|
||||||
|
} \
|
||||||
|
template <typename T> op_<op_##id, op_l, self_t, T> op(const self_t &, const T &) { \
|
||||||
|
return op_<op_##id, op_l, self_t, T>(); \
|
||||||
|
} \
|
||||||
|
template <typename T> op_<op_##id, op_r, T, self_t> op(const T &, const self_t &) { \
|
||||||
|
return op_<op_##id, op_r, T, self_t>(); \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define PYBIND11_INPLACE_OPERATOR(id, op, expr) \
|
||||||
|
template <typename B, typename L, typename R> struct op_impl<op_##id, op_l, B, L, R> { \
|
||||||
|
static char const* name() { return "__" #id "__"; } \
|
||||||
|
static auto execute(L &l, const R &r) -> decltype(expr) { return expr; } \
|
||||||
|
static B execute_cast(L &l, const R &r) { return B(expr); } \
|
||||||
|
}; \
|
||||||
|
template <typename T> op_<op_##id, op_l, self_t, T> op(const self_t &, const T &) { \
|
||||||
|
return op_<op_##id, op_l, self_t, T>(); \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define PYBIND11_UNARY_OPERATOR(id, op, expr) \
|
||||||
|
template <typename B, typename L> struct op_impl<op_##id, op_u, B, L, undefined_t> { \
|
||||||
|
static char const* name() { return "__" #id "__"; } \
|
||||||
|
static auto execute(const L &l) -> decltype(expr) { return expr; } \
|
||||||
|
static B execute_cast(const L &l) { return B(expr); } \
|
||||||
|
}; \
|
||||||
|
inline op_<op_##id, op_u, self_t, undefined_t> op(const self_t &) { \
|
||||||
|
return op_<op_##id, op_u, self_t, undefined_t>(); \
|
||||||
|
}
|
||||||
|
|
||||||
|
PYBIND11_BINARY_OPERATOR(sub, rsub, operator-, l - r)
|
||||||
|
PYBIND11_BINARY_OPERATOR(add, radd, operator+, l + r)
|
||||||
|
PYBIND11_BINARY_OPERATOR(mul, rmul, operator*, l * r)
|
||||||
|
PYBIND11_BINARY_OPERATOR(truediv, rtruediv, operator/, l / r)
|
||||||
|
PYBIND11_BINARY_OPERATOR(mod, rmod, operator%, l % r)
|
||||||
|
PYBIND11_BINARY_OPERATOR(lshift, rlshift, operator<<, l << r)
|
||||||
|
PYBIND11_BINARY_OPERATOR(rshift, rrshift, operator>>, l >> r)
|
||||||
|
PYBIND11_BINARY_OPERATOR(and, rand, operator&, l & r)
|
||||||
|
PYBIND11_BINARY_OPERATOR(xor, rxor, operator^, l ^ r)
|
||||||
|
PYBIND11_BINARY_OPERATOR(eq, eq, operator==, l == r)
|
||||||
|
PYBIND11_BINARY_OPERATOR(ne, ne, operator!=, l != r)
|
||||||
|
PYBIND11_BINARY_OPERATOR(or, ror, operator|, l | r)
|
||||||
|
PYBIND11_BINARY_OPERATOR(gt, lt, operator>, l > r)
|
||||||
|
PYBIND11_BINARY_OPERATOR(ge, le, operator>=, l >= r)
|
||||||
|
PYBIND11_BINARY_OPERATOR(lt, gt, operator<, l < r)
|
||||||
|
PYBIND11_BINARY_OPERATOR(le, ge, operator<=, l <= r)
|
||||||
|
//PYBIND11_BINARY_OPERATOR(pow, rpow, pow, std::pow(l, r))
|
||||||
|
PYBIND11_INPLACE_OPERATOR(iadd, operator+=, l += r)
|
||||||
|
PYBIND11_INPLACE_OPERATOR(isub, operator-=, l -= r)
|
||||||
|
PYBIND11_INPLACE_OPERATOR(imul, operator*=, l *= r)
|
||||||
|
PYBIND11_INPLACE_OPERATOR(itruediv, operator/=, l /= r)
|
||||||
|
PYBIND11_INPLACE_OPERATOR(imod, operator%=, l %= r)
|
||||||
|
PYBIND11_INPLACE_OPERATOR(ilshift, operator<<=, l <<= r)
|
||||||
|
PYBIND11_INPLACE_OPERATOR(irshift, operator>>=, l >>= r)
|
||||||
|
PYBIND11_INPLACE_OPERATOR(iand, operator&=, l &= r)
|
||||||
|
PYBIND11_INPLACE_OPERATOR(ixor, operator^=, l ^= r)
|
||||||
|
PYBIND11_INPLACE_OPERATOR(ior, operator|=, l |= r)
|
||||||
|
PYBIND11_UNARY_OPERATOR(neg, operator-, -l)
|
||||||
|
PYBIND11_UNARY_OPERATOR(pos, operator+, +l)
|
||||||
|
PYBIND11_UNARY_OPERATOR(abs, abs, std::abs(l))
|
||||||
|
PYBIND11_UNARY_OPERATOR(hash, hash, std::hash<L>()(l))
|
||||||
|
PYBIND11_UNARY_OPERATOR(invert, operator~, (~l))
|
||||||
|
PYBIND11_UNARY_OPERATOR(bool, operator!, !!l)
|
||||||
|
PYBIND11_UNARY_OPERATOR(int, int_, (int) l)
|
||||||
|
PYBIND11_UNARY_OPERATOR(float, float_, (double) l)
|
||||||
|
|
||||||
|
#undef PYBIND11_BINARY_OPERATOR
|
||||||
|
#undef PYBIND11_INPLACE_OPERATOR
|
||||||
|
#undef PYBIND11_UNARY_OPERATOR
|
||||||
|
NAMESPACE_END(detail)
|
||||||
|
|
||||||
|
using detail::self;
|
||||||
|
|
||||||
|
NAMESPACE_END(PYBIND11_NAMESPACE)
|
||||||
|
|
||||||
|
#if defined(_MSC_VER)
|
||||||
|
# pragma warning(pop)
|
||||||
|
#endif
|
65
3rdparty/pybind11/include/pybind11/options.h
vendored
Normal file
65
3rdparty/pybind11/include/pybind11/options.h
vendored
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
/*
|
||||||
|
pybind11/options.h: global settings that are configurable at runtime.
|
||||||
|
|
||||||
|
Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch>
|
||||||
|
|
||||||
|
All rights reserved. Use of this source code is governed by a
|
||||||
|
BSD-style license that can be found in the LICENSE file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "detail/common.h"
|
||||||
|
|
||||||
|
NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
|
||||||
|
|
||||||
|
class options {
|
||||||
|
public:
|
||||||
|
|
||||||
|
// Default RAII constructor, which leaves settings as they currently are.
|
||||||
|
options() : previous_state(global_state()) {}
|
||||||
|
|
||||||
|
// Class is non-copyable.
|
||||||
|
options(const options&) = delete;
|
||||||
|
options& operator=(const options&) = delete;
|
||||||
|
|
||||||
|
// Destructor, which restores settings that were in effect before.
|
||||||
|
~options() {
|
||||||
|
global_state() = previous_state;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Setter methods (affect the global state):
|
||||||
|
|
||||||
|
options& disable_user_defined_docstrings() & { global_state().show_user_defined_docstrings = false; return *this; }
|
||||||
|
|
||||||
|
options& enable_user_defined_docstrings() & { global_state().show_user_defined_docstrings = true; return *this; }
|
||||||
|
|
||||||
|
options& disable_function_signatures() & { global_state().show_function_signatures = false; return *this; }
|
||||||
|
|
||||||
|
options& enable_function_signatures() & { global_state().show_function_signatures = true; return *this; }
|
||||||
|
|
||||||
|
// Getter methods (return the global state):
|
||||||
|
|
||||||
|
static bool show_user_defined_docstrings() { return global_state().show_user_defined_docstrings; }
|
||||||
|
|
||||||
|
static bool show_function_signatures() { return global_state().show_function_signatures; }
|
||||||
|
|
||||||
|
// This type is not meant to be allocated on the heap.
|
||||||
|
void* operator new(size_t) = delete;
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
struct state {
|
||||||
|
bool show_user_defined_docstrings = true; //< Include user-supplied texts in docstrings.
|
||||||
|
bool show_function_signatures = true; //< Include auto-generated function signatures in docstrings.
|
||||||
|
};
|
||||||
|
|
||||||
|
static state &global_state() {
|
||||||
|
static state instance;
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
state previous_state;
|
||||||
|
};
|
||||||
|
|
||||||
|
NAMESPACE_END(PYBIND11_NAMESPACE)
|
2183
3rdparty/pybind11/include/pybind11/pybind11.h
vendored
Normal file
2183
3rdparty/pybind11/include/pybind11/pybind11.h
vendored
Normal file
File diff suppressed because it is too large
Load Diff
1484
3rdparty/pybind11/include/pybind11/pytypes.h
vendored
Normal file
1484
3rdparty/pybind11/include/pybind11/pytypes.h
vendored
Normal file
File diff suppressed because it is too large
Load Diff
386
3rdparty/pybind11/include/pybind11/stl.h
vendored
Normal file
386
3rdparty/pybind11/include/pybind11/stl.h
vendored
Normal file
@ -0,0 +1,386 @@
|
|||||||
|
/*
|
||||||
|
pybind11/stl.h: Transparent conversion for STL data types
|
||||||
|
|
||||||
|
Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch>
|
||||||
|
|
||||||
|
All rights reserved. Use of this source code is governed by a
|
||||||
|
BSD-style license that can be found in the LICENSE file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "pybind11.h"
|
||||||
|
#include <set>
|
||||||
|
#include <unordered_set>
|
||||||
|
#include <map>
|
||||||
|
#include <unordered_map>
|
||||||
|
#include <iostream>
|
||||||
|
#include <list>
|
||||||
|
#include <deque>
|
||||||
|
#include <valarray>
|
||||||
|
|
||||||
|
#if defined(_MSC_VER)
|
||||||
|
#pragma warning(push)
|
||||||
|
#pragma warning(disable: 4127) // warning C4127: Conditional expression is constant
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __has_include
|
||||||
|
// std::optional (but including it in c++14 mode isn't allowed)
|
||||||
|
# if defined(PYBIND11_CPP17) && __has_include(<optional>)
|
||||||
|
# include <optional>
|
||||||
|
# define PYBIND11_HAS_OPTIONAL 1
|
||||||
|
# endif
|
||||||
|
// std::experimental::optional (but not allowed in c++11 mode)
|
||||||
|
# if defined(PYBIND11_CPP14) && (__has_include(<experimental/optional>) && \
|
||||||
|
!__has_include(<optional>))
|
||||||
|
# include <experimental/optional>
|
||||||
|
# define PYBIND11_HAS_EXP_OPTIONAL 1
|
||||||
|
# endif
|
||||||
|
// std::variant
|
||||||
|
# if defined(PYBIND11_CPP17) && __has_include(<variant>)
|
||||||
|
# include <variant>
|
||||||
|
# define PYBIND11_HAS_VARIANT 1
|
||||||
|
# endif
|
||||||
|
#elif defined(_MSC_VER) && defined(PYBIND11_CPP17)
|
||||||
|
# include <optional>
|
||||||
|
# include <variant>
|
||||||
|
# define PYBIND11_HAS_OPTIONAL 1
|
||||||
|
# define PYBIND11_HAS_VARIANT 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
|
||||||
|
NAMESPACE_BEGIN(detail)
|
||||||
|
|
||||||
|
/// Extracts an const lvalue reference or rvalue reference for U based on the type of T (e.g. for
|
||||||
|
/// forwarding a container element). Typically used indirect via forwarded_type(), below.
|
||||||
|
template <typename T, typename U>
|
||||||
|
using forwarded_type = conditional_t<
|
||||||
|
std::is_lvalue_reference<T>::value, remove_reference_t<U> &, remove_reference_t<U> &&>;
|
||||||
|
|
||||||
|
/// Forwards a value U as rvalue or lvalue according to whether T is rvalue or lvalue; typically
|
||||||
|
/// used for forwarding a container's elements.
|
||||||
|
template <typename T, typename U>
|
||||||
|
forwarded_type<T, U> forward_like(U &&u) {
|
||||||
|
return std::forward<detail::forwarded_type<T, U>>(std::forward<U>(u));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Type, typename Key> struct set_caster {
|
||||||
|
using type = Type;
|
||||||
|
using key_conv = make_caster<Key>;
|
||||||
|
|
||||||
|
bool load(handle src, bool convert) {
|
||||||
|
if (!isinstance<pybind11::set>(src))
|
||||||
|
return false;
|
||||||
|
auto s = reinterpret_borrow<pybind11::set>(src);
|
||||||
|
value.clear();
|
||||||
|
for (auto entry : s) {
|
||||||
|
key_conv conv;
|
||||||
|
if (!conv.load(entry, convert))
|
||||||
|
return false;
|
||||||
|
value.insert(cast_op<Key &&>(std::move(conv)));
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
static handle cast(T &&src, return_value_policy policy, handle parent) {
|
||||||
|
if (!std::is_lvalue_reference<T>::value)
|
||||||
|
policy = return_value_policy_override<Key>::policy(policy);
|
||||||
|
pybind11::set s;
|
||||||
|
for (auto &&value : src) {
|
||||||
|
auto value_ = reinterpret_steal<object>(key_conv::cast(forward_like<T>(value), policy, parent));
|
||||||
|
if (!value_ || !s.add(value_))
|
||||||
|
return handle();
|
||||||
|
}
|
||||||
|
return s.release();
|
||||||
|
}
|
||||||
|
|
||||||
|
PYBIND11_TYPE_CASTER(type, _("Set[") + key_conv::name + _("]"));
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename Type, typename Key, typename Value> struct map_caster {
|
||||||
|
using key_conv = make_caster<Key>;
|
||||||
|
using value_conv = make_caster<Value>;
|
||||||
|
|
||||||
|
bool load(handle src, bool convert) {
|
||||||
|
if (!isinstance<dict>(src))
|
||||||
|
return false;
|
||||||
|
auto d = reinterpret_borrow<dict>(src);
|
||||||
|
value.clear();
|
||||||
|
for (auto it : d) {
|
||||||
|
key_conv kconv;
|
||||||
|
value_conv vconv;
|
||||||
|
if (!kconv.load(it.first.ptr(), convert) ||
|
||||||
|
!vconv.load(it.second.ptr(), convert))
|
||||||
|
return false;
|
||||||
|
value.emplace(cast_op<Key &&>(std::move(kconv)), cast_op<Value &&>(std::move(vconv)));
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
static handle cast(T &&src, return_value_policy policy, handle parent) {
|
||||||
|
dict d;
|
||||||
|
return_value_policy policy_key = policy;
|
||||||
|
return_value_policy policy_value = policy;
|
||||||
|
if (!std::is_lvalue_reference<T>::value) {
|
||||||
|
policy_key = return_value_policy_override<Key>::policy(policy_key);
|
||||||
|
policy_value = return_value_policy_override<Value>::policy(policy_value);
|
||||||
|
}
|
||||||
|
for (auto &&kv : src) {
|
||||||
|
auto key = reinterpret_steal<object>(key_conv::cast(forward_like<T>(kv.first), policy_key, parent));
|
||||||
|
auto value = reinterpret_steal<object>(value_conv::cast(forward_like<T>(kv.second), policy_value, parent));
|
||||||
|
if (!key || !value)
|
||||||
|
return handle();
|
||||||
|
d[key] = value;
|
||||||
|
}
|
||||||
|
return d.release();
|
||||||
|
}
|
||||||
|
|
||||||
|
PYBIND11_TYPE_CASTER(Type, _("Dict[") + key_conv::name + _(", ") + value_conv::name + _("]"));
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename Type, typename Value> struct list_caster {
|
||||||
|
using value_conv = make_caster<Value>;
|
||||||
|
|
||||||
|
bool load(handle src, bool convert) {
|
||||||
|
if (!isinstance<sequence>(src) || isinstance<str>(src))
|
||||||
|
return false;
|
||||||
|
auto s = reinterpret_borrow<sequence>(src);
|
||||||
|
value.clear();
|
||||||
|
reserve_maybe(s, &value);
|
||||||
|
for (auto it : s) {
|
||||||
|
value_conv conv;
|
||||||
|
if (!conv.load(it, convert))
|
||||||
|
return false;
|
||||||
|
value.push_back(cast_op<Value &&>(std::move(conv)));
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
template <typename T = Type,
|
||||||
|
enable_if_t<std::is_same<decltype(std::declval<T>().reserve(0)), void>::value, int> = 0>
|
||||||
|
void reserve_maybe(sequence s, Type *) { value.reserve(s.size()); }
|
||||||
|
void reserve_maybe(sequence, void *) { }
|
||||||
|
|
||||||
|
public:
|
||||||
|
template <typename T>
|
||||||
|
static handle cast(T &&src, return_value_policy policy, handle parent) {
|
||||||
|
if (!std::is_lvalue_reference<T>::value)
|
||||||
|
policy = return_value_policy_override<Value>::policy(policy);
|
||||||
|
list l(src.size());
|
||||||
|
size_t index = 0;
|
||||||
|
for (auto &&value : src) {
|
||||||
|
auto value_ = reinterpret_steal<object>(value_conv::cast(forward_like<T>(value), policy, parent));
|
||||||
|
if (!value_)
|
||||||
|
return handle();
|
||||||
|
PyList_SET_ITEM(l.ptr(), (ssize_t) index++, value_.release().ptr()); // steals a reference
|
||||||
|
}
|
||||||
|
return l.release();
|
||||||
|
}
|
||||||
|
|
||||||
|
PYBIND11_TYPE_CASTER(Type, _("List[") + value_conv::name + _("]"));
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename Type, typename Alloc> struct type_caster<std::vector<Type, Alloc>>
|
||||||
|
: list_caster<std::vector<Type, Alloc>, Type> { };
|
||||||
|
|
||||||
|
template <typename Type, typename Alloc> struct type_caster<std::deque<Type, Alloc>>
|
||||||
|
: list_caster<std::deque<Type, Alloc>, Type> { };
|
||||||
|
|
||||||
|
template <typename Type, typename Alloc> struct type_caster<std::list<Type, Alloc>>
|
||||||
|
: list_caster<std::list<Type, Alloc>, Type> { };
|
||||||
|
|
||||||
|
template <typename ArrayType, typename Value, bool Resizable, size_t Size = 0> struct array_caster {
|
||||||
|
using value_conv = make_caster<Value>;
|
||||||
|
|
||||||
|
private:
|
||||||
|
template <bool R = Resizable>
|
||||||
|
bool require_size(enable_if_t<R, size_t> size) {
|
||||||
|
if (value.size() != size)
|
||||||
|
value.resize(size);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
template <bool R = Resizable>
|
||||||
|
bool require_size(enable_if_t<!R, size_t> size) {
|
||||||
|
return size == Size;
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
bool load(handle src, bool convert) {
|
||||||
|
if (!isinstance<sequence>(src))
|
||||||
|
return false;
|
||||||
|
auto l = reinterpret_borrow<sequence>(src);
|
||||||
|
if (!require_size(l.size()))
|
||||||
|
return false;
|
||||||
|
size_t ctr = 0;
|
||||||
|
for (auto it : l) {
|
||||||
|
value_conv conv;
|
||||||
|
if (!conv.load(it, convert))
|
||||||
|
return false;
|
||||||
|
value[ctr++] = cast_op<Value &&>(std::move(conv));
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
static handle cast(T &&src, return_value_policy policy, handle parent) {
|
||||||
|
list l(src.size());
|
||||||
|
size_t index = 0;
|
||||||
|
for (auto &&value : src) {
|
||||||
|
auto value_ = reinterpret_steal<object>(value_conv::cast(forward_like<T>(value), policy, parent));
|
||||||
|
if (!value_)
|
||||||
|
return handle();
|
||||||
|
PyList_SET_ITEM(l.ptr(), (ssize_t) index++, value_.release().ptr()); // steals a reference
|
||||||
|
}
|
||||||
|
return l.release();
|
||||||
|
}
|
||||||
|
|
||||||
|
PYBIND11_TYPE_CASTER(ArrayType, _("List[") + value_conv::name + _<Resizable>(_(""), _("[") + _<Size>() + _("]")) + _("]"));
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename Type, size_t Size> struct type_caster<std::array<Type, Size>>
|
||||||
|
: array_caster<std::array<Type, Size>, Type, false, Size> { };
|
||||||
|
|
||||||
|
template <typename Type> struct type_caster<std::valarray<Type>>
|
||||||
|
: array_caster<std::valarray<Type>, Type, true> { };
|
||||||
|
|
||||||
|
template <typename Key, typename Compare, typename Alloc> struct type_caster<std::set<Key, Compare, Alloc>>
|
||||||
|
: set_caster<std::set<Key, Compare, Alloc>, Key> { };
|
||||||
|
|
||||||
|
template <typename Key, typename Hash, typename Equal, typename Alloc> struct type_caster<std::unordered_set<Key, Hash, Equal, Alloc>>
|
||||||
|
: set_caster<std::unordered_set<Key, Hash, Equal, Alloc>, Key> { };
|
||||||
|
|
||||||
|
template <typename Key, typename Value, typename Compare, typename Alloc> struct type_caster<std::map<Key, Value, Compare, Alloc>>
|
||||||
|
: map_caster<std::map<Key, Value, Compare, Alloc>, Key, Value> { };
|
||||||
|
|
||||||
|
template <typename Key, typename Value, typename Hash, typename Equal, typename Alloc> struct type_caster<std::unordered_map<Key, Value, Hash, Equal, Alloc>>
|
||||||
|
: map_caster<std::unordered_map<Key, Value, Hash, Equal, Alloc>, Key, Value> { };
|
||||||
|
|
||||||
|
// This type caster is intended to be used for std::optional and std::experimental::optional
|
||||||
|
template<typename T> struct optional_caster {
|
||||||
|
using value_conv = make_caster<typename T::value_type>;
|
||||||
|
|
||||||
|
template <typename T_>
|
||||||
|
static handle cast(T_ &&src, return_value_policy policy, handle parent) {
|
||||||
|
if (!src)
|
||||||
|
return none().inc_ref();
|
||||||
|
policy = return_value_policy_override<typename T::value_type>::policy(policy);
|
||||||
|
return value_conv::cast(*std::forward<T_>(src), policy, parent);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool load(handle src, bool convert) {
|
||||||
|
if (!src) {
|
||||||
|
return false;
|
||||||
|
} else if (src.is_none()) {
|
||||||
|
return true; // default-constructed value is already empty
|
||||||
|
}
|
||||||
|
value_conv inner_caster;
|
||||||
|
if (!inner_caster.load(src, convert))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
value.emplace(cast_op<typename T::value_type &&>(std::move(inner_caster)));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
PYBIND11_TYPE_CASTER(T, _("Optional[") + value_conv::name + _("]"));
|
||||||
|
};
|
||||||
|
|
||||||
|
#if PYBIND11_HAS_OPTIONAL
|
||||||
|
template<typename T> struct type_caster<std::optional<T>>
|
||||||
|
: public optional_caster<std::optional<T>> {};
|
||||||
|
|
||||||
|
template<> struct type_caster<std::nullopt_t>
|
||||||
|
: public void_caster<std::nullopt_t> {};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if PYBIND11_HAS_EXP_OPTIONAL
|
||||||
|
template<typename T> struct type_caster<std::experimental::optional<T>>
|
||||||
|
: public optional_caster<std::experimental::optional<T>> {};
|
||||||
|
|
||||||
|
template<> struct type_caster<std::experimental::nullopt_t>
|
||||||
|
: public void_caster<std::experimental::nullopt_t> {};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/// Visit a variant and cast any found type to Python
|
||||||
|
struct variant_caster_visitor {
|
||||||
|
return_value_policy policy;
|
||||||
|
handle parent;
|
||||||
|
|
||||||
|
using result_type = handle; // required by boost::variant in C++11
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
result_type operator()(T &&src) const {
|
||||||
|
return make_caster<T>::cast(std::forward<T>(src), policy, parent);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Helper class which abstracts away variant's `visit` function. `std::variant` and similar
|
||||||
|
/// `namespace::variant` types which provide a `namespace::visit()` function are handled here
|
||||||
|
/// automatically using argument-dependent lookup. Users can provide specializations for other
|
||||||
|
/// variant-like classes, e.g. `boost::variant` and `boost::apply_visitor`.
|
||||||
|
template <template<typename...> class Variant>
|
||||||
|
struct visit_helper {
|
||||||
|
template <typename... Args>
|
||||||
|
static auto call(Args &&...args) -> decltype(visit(std::forward<Args>(args)...)) {
|
||||||
|
return visit(std::forward<Args>(args)...);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Generic variant caster
|
||||||
|
template <typename Variant> struct variant_caster;
|
||||||
|
|
||||||
|
template <template<typename...> class V, typename... Ts>
|
||||||
|
struct variant_caster<V<Ts...>> {
|
||||||
|
static_assert(sizeof...(Ts) > 0, "Variant must consist of at least one alternative.");
|
||||||
|
|
||||||
|
template <typename U, typename... Us>
|
||||||
|
bool load_alternative(handle src, bool convert, type_list<U, Us...>) {
|
||||||
|
auto caster = make_caster<U>();
|
||||||
|
if (caster.load(src, convert)) {
|
||||||
|
value = cast_op<U>(caster);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return load_alternative(src, convert, type_list<Us...>{});
|
||||||
|
}
|
||||||
|
|
||||||
|
bool load_alternative(handle, bool, type_list<>) { return false; }
|
||||||
|
|
||||||
|
bool load(handle src, bool convert) {
|
||||||
|
// Do a first pass without conversions to improve constructor resolution.
|
||||||
|
// E.g. `py::int_(1).cast<variant<double, int>>()` needs to fill the `int`
|
||||||
|
// slot of the variant. Without two-pass loading `double` would be filled
|
||||||
|
// because it appears first and a conversion is possible.
|
||||||
|
if (convert && load_alternative(src, false, type_list<Ts...>{}))
|
||||||
|
return true;
|
||||||
|
return load_alternative(src, convert, type_list<Ts...>{});
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Variant>
|
||||||
|
static handle cast(Variant &&src, return_value_policy policy, handle parent) {
|
||||||
|
return visit_helper<V>::call(variant_caster_visitor{policy, parent},
|
||||||
|
std::forward<Variant>(src));
|
||||||
|
}
|
||||||
|
|
||||||
|
using Type = V<Ts...>;
|
||||||
|
PYBIND11_TYPE_CASTER(Type, _("Union[") + detail::concat(make_caster<Ts>::name...) + _("]"));
|
||||||
|
};
|
||||||
|
|
||||||
|
#if PYBIND11_HAS_VARIANT
|
||||||
|
template <typename... Ts>
|
||||||
|
struct type_caster<std::variant<Ts...>> : variant_caster<std::variant<Ts...>> { };
|
||||||
|
#endif
|
||||||
|
|
||||||
|
NAMESPACE_END(detail)
|
||||||
|
|
||||||
|
inline std::ostream &operator<<(std::ostream &os, const handle &obj) {
|
||||||
|
os << (std::string) str(obj);
|
||||||
|
return os;
|
||||||
|
}
|
||||||
|
|
||||||
|
NAMESPACE_END(PYBIND11_NAMESPACE)
|
||||||
|
|
||||||
|
#if defined(_MSC_VER)
|
||||||
|
#pragma warning(pop)
|
||||||
|
#endif
|
656
3rdparty/pybind11/include/pybind11/stl_bind.h
vendored
Normal file
656
3rdparty/pybind11/include/pybind11/stl_bind.h
vendored
Normal file
@ -0,0 +1,656 @@
|
|||||||
|
/*
|
||||||
|
pybind11/std_bind.h: Binding generators for STL data types
|
||||||
|
|
||||||
|
Copyright (c) 2016 Sergey Lyskov and Wenzel Jakob
|
||||||
|
|
||||||
|
All rights reserved. Use of this source code is governed by a
|
||||||
|
BSD-style license that can be found in the LICENSE file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "detail/common.h"
|
||||||
|
#include "operators.h"
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
|
NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
|
||||||
|
NAMESPACE_BEGIN(detail)
|
||||||
|
|
||||||
|
/* SFINAE helper class used by 'is_comparable */
|
||||||
|
template <typename T> struct container_traits {
|
||||||
|
template <typename T2> static std::true_type test_comparable(decltype(std::declval<const T2 &>() == std::declval<const T2 &>())*);
|
||||||
|
template <typename T2> static std::false_type test_comparable(...);
|
||||||
|
template <typename T2> static std::true_type test_value(typename T2::value_type *);
|
||||||
|
template <typename T2> static std::false_type test_value(...);
|
||||||
|
template <typename T2> static std::true_type test_pair(typename T2::first_type *, typename T2::second_type *);
|
||||||
|
template <typename T2> static std::false_type test_pair(...);
|
||||||
|
|
||||||
|
static constexpr const bool is_comparable = std::is_same<std::true_type, decltype(test_comparable<T>(nullptr))>::value;
|
||||||
|
static constexpr const bool is_pair = std::is_same<std::true_type, decltype(test_pair<T>(nullptr, nullptr))>::value;
|
||||||
|
static constexpr const bool is_vector = std::is_same<std::true_type, decltype(test_value<T>(nullptr))>::value;
|
||||||
|
static constexpr const bool is_element = !is_pair && !is_vector;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Default: is_comparable -> std::false_type */
|
||||||
|
template <typename T, typename SFINAE = void>
|
||||||
|
struct is_comparable : std::false_type { };
|
||||||
|
|
||||||
|
/* For non-map data structures, check whether operator== can be instantiated */
|
||||||
|
template <typename T>
|
||||||
|
struct is_comparable<
|
||||||
|
T, enable_if_t<container_traits<T>::is_element &&
|
||||||
|
container_traits<T>::is_comparable>>
|
||||||
|
: std::true_type { };
|
||||||
|
|
||||||
|
/* For a vector/map data structure, recursively check the value type (which is std::pair for maps) */
|
||||||
|
template <typename T>
|
||||||
|
struct is_comparable<T, enable_if_t<container_traits<T>::is_vector>> {
|
||||||
|
static constexpr const bool value =
|
||||||
|
is_comparable<typename T::value_type>::value;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* For pairs, recursively check the two data types */
|
||||||
|
template <typename T>
|
||||||
|
struct is_comparable<T, enable_if_t<container_traits<T>::is_pair>> {
|
||||||
|
static constexpr const bool value =
|
||||||
|
is_comparable<typename T::first_type>::value &&
|
||||||
|
is_comparable<typename T::second_type>::value;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Fallback functions */
|
||||||
|
template <typename, typename, typename... Args> void vector_if_copy_constructible(const Args &...) { }
|
||||||
|
template <typename, typename, typename... Args> void vector_if_equal_operator(const Args &...) { }
|
||||||
|
template <typename, typename, typename... Args> void vector_if_insertion_operator(const Args &...) { }
|
||||||
|
template <typename, typename, typename... Args> void vector_modifiers(const Args &...) { }
|
||||||
|
|
||||||
|
template<typename Vector, typename Class_>
|
||||||
|
void vector_if_copy_constructible(enable_if_t<is_copy_constructible<Vector>::value, Class_> &cl) {
|
||||||
|
cl.def(init<const Vector &>(), "Copy constructor");
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename Vector, typename Class_>
|
||||||
|
void vector_if_equal_operator(enable_if_t<is_comparable<Vector>::value, Class_> &cl) {
|
||||||
|
using T = typename Vector::value_type;
|
||||||
|
|
||||||
|
cl.def(self == self);
|
||||||
|
cl.def(self != self);
|
||||||
|
|
||||||
|
cl.def("count",
|
||||||
|
[](const Vector &v, const T &x) {
|
||||||
|
return std::count(v.begin(), v.end(), x);
|
||||||
|
},
|
||||||
|
arg("x"),
|
||||||
|
"Return the number of times ``x`` appears in the list"
|
||||||
|
);
|
||||||
|
|
||||||
|
cl.def("remove", [](Vector &v, const T &x) {
|
||||||
|
auto p = std::find(v.begin(), v.end(), x);
|
||||||
|
if (p != v.end())
|
||||||
|
v.erase(p);
|
||||||
|
else
|
||||||
|
throw value_error();
|
||||||
|
},
|
||||||
|
arg("x"),
|
||||||
|
"Remove the first item from the list whose value is x. "
|
||||||
|
"It is an error if there is no such item."
|
||||||
|
);
|
||||||
|
|
||||||
|
cl.def("__contains__",
|
||||||
|
[](const Vector &v, const T &x) {
|
||||||
|
return std::find(v.begin(), v.end(), x) != v.end();
|
||||||
|
},
|
||||||
|
arg("x"),
|
||||||
|
"Return true the container contains ``x``"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Vector modifiers -- requires a copyable vector_type:
|
||||||
|
// (Technically, some of these (pop and __delitem__) don't actually require copyability, but it seems
|
||||||
|
// silly to allow deletion but not insertion, so include them here too.)
|
||||||
|
template <typename Vector, typename Class_>
|
||||||
|
void vector_modifiers(enable_if_t<is_copy_constructible<typename Vector::value_type>::value, Class_> &cl) {
|
||||||
|
using T = typename Vector::value_type;
|
||||||
|
using SizeType = typename Vector::size_type;
|
||||||
|
using DiffType = typename Vector::difference_type;
|
||||||
|
|
||||||
|
auto wrap_i = [](DiffType i, SizeType n) {
|
||||||
|
if (i < 0)
|
||||||
|
i += n;
|
||||||
|
if (i < 0 || (SizeType)i >= n)
|
||||||
|
throw index_error();
|
||||||
|
return i;
|
||||||
|
};
|
||||||
|
|
||||||
|
cl.def("append",
|
||||||
|
[](Vector &v, const T &value) { v.push_back(value); },
|
||||||
|
arg("x"),
|
||||||
|
"Add an item to the end of the list");
|
||||||
|
|
||||||
|
cl.def(init([](iterable it) {
|
||||||
|
auto v = std::unique_ptr<Vector>(new Vector());
|
||||||
|
v->reserve(len_hint(it));
|
||||||
|
for (handle h : it)
|
||||||
|
v->push_back(h.cast<T>());
|
||||||
|
return v.release();
|
||||||
|
}));
|
||||||
|
|
||||||
|
cl.def("clear",
|
||||||
|
[](Vector &v) {
|
||||||
|
v.clear();
|
||||||
|
},
|
||||||
|
"Clear the contents"
|
||||||
|
);
|
||||||
|
|
||||||
|
cl.def("extend",
|
||||||
|
[](Vector &v, const Vector &src) {
|
||||||
|
v.insert(v.end(), src.begin(), src.end());
|
||||||
|
},
|
||||||
|
arg("L"),
|
||||||
|
"Extend the list by appending all the items in the given list"
|
||||||
|
);
|
||||||
|
|
||||||
|
cl.def("extend",
|
||||||
|
[](Vector &v, iterable it) {
|
||||||
|
const size_t old_size = v.size();
|
||||||
|
v.reserve(old_size + len_hint(it));
|
||||||
|
try {
|
||||||
|
for (handle h : it) {
|
||||||
|
v.push_back(h.cast<T>());
|
||||||
|
}
|
||||||
|
} catch (const cast_error &) {
|
||||||
|
v.erase(v.begin() + static_cast<typename Vector::difference_type>(old_size), v.end());
|
||||||
|
try {
|
||||||
|
v.shrink_to_fit();
|
||||||
|
} catch (const std::exception &) {
|
||||||
|
// Do nothing
|
||||||
|
}
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
arg("L"),
|
||||||
|
"Extend the list by appending all the items in the given list"
|
||||||
|
);
|
||||||
|
|
||||||
|
cl.def("insert",
|
||||||
|
[](Vector &v, DiffType i, const T &x) {
|
||||||
|
// Can't use wrap_i; i == v.size() is OK
|
||||||
|
if (i < 0)
|
||||||
|
i += v.size();
|
||||||
|
if (i < 0 || (SizeType)i > v.size())
|
||||||
|
throw index_error();
|
||||||
|
v.insert(v.begin() + i, x);
|
||||||
|
},
|
||||||
|
arg("i") , arg("x"),
|
||||||
|
"Insert an item at a given position."
|
||||||
|
);
|
||||||
|
|
||||||
|
cl.def("pop",
|
||||||
|
[](Vector &v) {
|
||||||
|
if (v.empty())
|
||||||
|
throw index_error();
|
||||||
|
T t = v.back();
|
||||||
|
v.pop_back();
|
||||||
|
return t;
|
||||||
|
},
|
||||||
|
"Remove and return the last item"
|
||||||
|
);
|
||||||
|
|
||||||
|
cl.def("pop",
|
||||||
|
[wrap_i](Vector &v, DiffType i) {
|
||||||
|
i = wrap_i(i, v.size());
|
||||||
|
T t = v[(SizeType) i];
|
||||||
|
v.erase(v.begin() + i);
|
||||||
|
return t;
|
||||||
|
},
|
||||||
|
arg("i"),
|
||||||
|
"Remove and return the item at index ``i``"
|
||||||
|
);
|
||||||
|
|
||||||
|
cl.def("__setitem__",
|
||||||
|
[wrap_i](Vector &v, DiffType i, const T &t) {
|
||||||
|
i = wrap_i(i, v.size());
|
||||||
|
v[(SizeType)i] = t;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
/// Slicing protocol
|
||||||
|
cl.def("__getitem__",
|
||||||
|
[](const Vector &v, slice slice) -> Vector * {
|
||||||
|
size_t start, stop, step, slicelength;
|
||||||
|
|
||||||
|
if (!slice.compute(v.size(), &start, &stop, &step, &slicelength))
|
||||||
|
throw error_already_set();
|
||||||
|
|
||||||
|
Vector *seq = new Vector();
|
||||||
|
seq->reserve((size_t) slicelength);
|
||||||
|
|
||||||
|
for (size_t i=0; i<slicelength; ++i) {
|
||||||
|
seq->push_back(v[start]);
|
||||||
|
start += step;
|
||||||
|
}
|
||||||
|
return seq;
|
||||||
|
},
|
||||||
|
arg("s"),
|
||||||
|
"Retrieve list elements using a slice object"
|
||||||
|
);
|
||||||
|
|
||||||
|
cl.def("__setitem__",
|
||||||
|
[](Vector &v, slice slice, const Vector &value) {
|
||||||
|
size_t start, stop, step, slicelength;
|
||||||
|
if (!slice.compute(v.size(), &start, &stop, &step, &slicelength))
|
||||||
|
throw error_already_set();
|
||||||
|
|
||||||
|
if (slicelength != value.size())
|
||||||
|
throw std::runtime_error("Left and right hand size of slice assignment have different sizes!");
|
||||||
|
|
||||||
|
for (size_t i=0; i<slicelength; ++i) {
|
||||||
|
v[start] = value[i];
|
||||||
|
start += step;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Assign list elements using a slice object"
|
||||||
|
);
|
||||||
|
|
||||||
|
cl.def("__delitem__",
|
||||||
|
[wrap_i](Vector &v, DiffType i) {
|
||||||
|
i = wrap_i(i, v.size());
|
||||||
|
v.erase(v.begin() + i);
|
||||||
|
},
|
||||||
|
"Delete the list elements at index ``i``"
|
||||||
|
);
|
||||||
|
|
||||||
|
cl.def("__delitem__",
|
||||||
|
[](Vector &v, slice slice) {
|
||||||
|
size_t start, stop, step, slicelength;
|
||||||
|
|
||||||
|
if (!slice.compute(v.size(), &start, &stop, &step, &slicelength))
|
||||||
|
throw error_already_set();
|
||||||
|
|
||||||
|
if (step == 1 && false) {
|
||||||
|
v.erase(v.begin() + (DiffType) start, v.begin() + DiffType(start + slicelength));
|
||||||
|
} else {
|
||||||
|
for (size_t i = 0; i < slicelength; ++i) {
|
||||||
|
v.erase(v.begin() + DiffType(start));
|
||||||
|
start += step - 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Delete list elements using a slice object"
|
||||||
|
);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the type has an operator[] that doesn't return a reference (most notably std::vector<bool>),
|
||||||
|
// we have to access by copying; otherwise we return by reference.
|
||||||
|
template <typename Vector> using vector_needs_copy = negation<
|
||||||
|
std::is_same<decltype(std::declval<Vector>()[typename Vector::size_type()]), typename Vector::value_type &>>;
|
||||||
|
|
||||||
|
// The usual case: access and iterate by reference
|
||||||
|
template <typename Vector, typename Class_>
|
||||||
|
void vector_accessor(enable_if_t<!vector_needs_copy<Vector>::value, Class_> &cl) {
|
||||||
|
using T = typename Vector::value_type;
|
||||||
|
using SizeType = typename Vector::size_type;
|
||||||
|
using DiffType = typename Vector::difference_type;
|
||||||
|
using ItType = typename Vector::iterator;
|
||||||
|
|
||||||
|
auto wrap_i = [](DiffType i, SizeType n) {
|
||||||
|
if (i < 0)
|
||||||
|
i += n;
|
||||||
|
if (i < 0 || (SizeType)i >= n)
|
||||||
|
throw index_error();
|
||||||
|
return i;
|
||||||
|
};
|
||||||
|
|
||||||
|
cl.def("__getitem__",
|
||||||
|
[wrap_i](Vector &v, DiffType i) -> T & {
|
||||||
|
i = wrap_i(i, v.size());
|
||||||
|
return v[(SizeType)i];
|
||||||
|
},
|
||||||
|
return_value_policy::reference_internal // ref + keepalive
|
||||||
|
);
|
||||||
|
|
||||||
|
cl.def("__iter__",
|
||||||
|
[](Vector &v) {
|
||||||
|
return make_iterator<
|
||||||
|
return_value_policy::reference_internal, ItType, ItType, T&>(
|
||||||
|
v.begin(), v.end());
|
||||||
|
},
|
||||||
|
keep_alive<0, 1>() /* Essential: keep list alive while iterator exists */
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// The case for special objects, like std::vector<bool>, that have to be returned-by-copy:
|
||||||
|
template <typename Vector, typename Class_>
|
||||||
|
void vector_accessor(enable_if_t<vector_needs_copy<Vector>::value, Class_> &cl) {
|
||||||
|
using T = typename Vector::value_type;
|
||||||
|
using SizeType = typename Vector::size_type;
|
||||||
|
using DiffType = typename Vector::difference_type;
|
||||||
|
using ItType = typename Vector::iterator;
|
||||||
|
cl.def("__getitem__",
|
||||||
|
[](const Vector &v, DiffType i) -> T {
|
||||||
|
if (i < 0 && (i += v.size()) < 0)
|
||||||
|
throw index_error();
|
||||||
|
if ((SizeType)i >= v.size())
|
||||||
|
throw index_error();
|
||||||
|
return v[(SizeType)i];
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
cl.def("__iter__",
|
||||||
|
[](Vector &v) {
|
||||||
|
return make_iterator<
|
||||||
|
return_value_policy::copy, ItType, ItType, T>(
|
||||||
|
v.begin(), v.end());
|
||||||
|
},
|
||||||
|
keep_alive<0, 1>() /* Essential: keep list alive while iterator exists */
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Vector, typename Class_> auto vector_if_insertion_operator(Class_ &cl, std::string const &name)
|
||||||
|
-> decltype(std::declval<std::ostream&>() << std::declval<typename Vector::value_type>(), void()) {
|
||||||
|
using size_type = typename Vector::size_type;
|
||||||
|
|
||||||
|
cl.def("__repr__",
|
||||||
|
[name](Vector &v) {
|
||||||
|
std::ostringstream s;
|
||||||
|
s << name << '[';
|
||||||
|
for (size_type i=0; i < v.size(); ++i) {
|
||||||
|
s << v[i];
|
||||||
|
if (i != v.size() - 1)
|
||||||
|
s << ", ";
|
||||||
|
}
|
||||||
|
s << ']';
|
||||||
|
return s.str();
|
||||||
|
},
|
||||||
|
"Return the canonical string representation of this list."
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Provide the buffer interface for vectors if we have data() and we have a format for it
|
||||||
|
// GCC seems to have "void std::vector<bool>::data()" - doing SFINAE on the existence of data() is insufficient, we need to check it returns an appropriate pointer
|
||||||
|
template <typename Vector, typename = void>
|
||||||
|
struct vector_has_data_and_format : std::false_type {};
|
||||||
|
template <typename Vector>
|
||||||
|
struct vector_has_data_and_format<Vector, enable_if_t<std::is_same<decltype(format_descriptor<typename Vector::value_type>::format(), std::declval<Vector>().data()), typename Vector::value_type*>::value>> : std::true_type {};
|
||||||
|
|
||||||
|
// Add the buffer interface to a vector
|
||||||
|
template <typename Vector, typename Class_, typename... Args>
|
||||||
|
enable_if_t<detail::any_of<std::is_same<Args, buffer_protocol>...>::value>
|
||||||
|
vector_buffer(Class_& cl) {
|
||||||
|
using T = typename Vector::value_type;
|
||||||
|
|
||||||
|
static_assert(vector_has_data_and_format<Vector>::value, "There is not an appropriate format descriptor for this vector");
|
||||||
|
|
||||||
|
// numpy.h declares this for arbitrary types, but it may raise an exception and crash hard at runtime if PYBIND11_NUMPY_DTYPE hasn't been called, so check here
|
||||||
|
format_descriptor<T>::format();
|
||||||
|
|
||||||
|
cl.def_buffer([](Vector& v) -> buffer_info {
|
||||||
|
return buffer_info(v.data(), static_cast<ssize_t>(sizeof(T)), format_descriptor<T>::format(), 1, {v.size()}, {sizeof(T)});
|
||||||
|
});
|
||||||
|
|
||||||
|
cl.def(init([](buffer buf) {
|
||||||
|
auto info = buf.request();
|
||||||
|
if (info.ndim != 1 || info.strides[0] % static_cast<ssize_t>(sizeof(T)))
|
||||||
|
throw type_error("Only valid 1D buffers can be copied to a vector");
|
||||||
|
if (!detail::compare_buffer_info<T>::compare(info) || (ssize_t) sizeof(T) != info.itemsize)
|
||||||
|
throw type_error("Format mismatch (Python: " + info.format + " C++: " + format_descriptor<T>::format() + ")");
|
||||||
|
|
||||||
|
auto vec = std::unique_ptr<Vector>(new Vector());
|
||||||
|
vec->reserve((size_t) info.shape[0]);
|
||||||
|
T *p = static_cast<T*>(info.ptr);
|
||||||
|
ssize_t step = info.strides[0] / static_cast<ssize_t>(sizeof(T));
|
||||||
|
T *end = p + info.shape[0] * step;
|
||||||
|
for (; p != end; p += step)
|
||||||
|
vec->push_back(*p);
|
||||||
|
return vec.release();
|
||||||
|
}));
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Vector, typename Class_, typename... Args>
|
||||||
|
enable_if_t<!detail::any_of<std::is_same<Args, buffer_protocol>...>::value> vector_buffer(Class_&) {}
|
||||||
|
|
||||||
|
NAMESPACE_END(detail)
|
||||||
|
|
||||||
|
//
|
||||||
|
// std::vector
|
||||||
|
//
|
||||||
|
template <typename Vector, typename holder_type = std::unique_ptr<Vector>, typename... Args>
|
||||||
|
class_<Vector, holder_type> bind_vector(handle scope, std::string const &name, Args&&... args) {
|
||||||
|
using Class_ = class_<Vector, holder_type>;
|
||||||
|
|
||||||
|
// If the value_type is unregistered (e.g. a converting type) or is itself registered
|
||||||
|
// module-local then make the vector binding module-local as well:
|
||||||
|
using vtype = typename Vector::value_type;
|
||||||
|
auto vtype_info = detail::get_type_info(typeid(vtype));
|
||||||
|
bool local = !vtype_info || vtype_info->module_local;
|
||||||
|
|
||||||
|
Class_ cl(scope, name.c_str(), pybind11::module_local(local), std::forward<Args>(args)...);
|
||||||
|
|
||||||
|
// Declare the buffer interface if a buffer_protocol() is passed in
|
||||||
|
detail::vector_buffer<Vector, Class_, Args...>(cl);
|
||||||
|
|
||||||
|
cl.def(init<>());
|
||||||
|
|
||||||
|
// Register copy constructor (if possible)
|
||||||
|
detail::vector_if_copy_constructible<Vector, Class_>(cl);
|
||||||
|
|
||||||
|
// Register comparison-related operators and functions (if possible)
|
||||||
|
detail::vector_if_equal_operator<Vector, Class_>(cl);
|
||||||
|
|
||||||
|
// Register stream insertion operator (if possible)
|
||||||
|
detail::vector_if_insertion_operator<Vector, Class_>(cl, name);
|
||||||
|
|
||||||
|
// Modifiers require copyable vector value type
|
||||||
|
detail::vector_modifiers<Vector, Class_>(cl);
|
||||||
|
|
||||||
|
// Accessor and iterator; return by value if copyable, otherwise we return by ref + keep-alive
|
||||||
|
detail::vector_accessor<Vector, Class_>(cl);
|
||||||
|
|
||||||
|
cl.def("__bool__",
|
||||||
|
[](const Vector &v) -> bool {
|
||||||
|
return !v.empty();
|
||||||
|
},
|
||||||
|
"Check whether the list is nonempty"
|
||||||
|
);
|
||||||
|
|
||||||
|
cl.def("__len__", &Vector::size);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
// C++ style functions deprecated, leaving it here as an example
|
||||||
|
cl.def(init<size_type>());
|
||||||
|
|
||||||
|
cl.def("resize",
|
||||||
|
(void (Vector::*) (size_type count)) & Vector::resize,
|
||||||
|
"changes the number of elements stored");
|
||||||
|
|
||||||
|
cl.def("erase",
|
||||||
|
[](Vector &v, SizeType i) {
|
||||||
|
if (i >= v.size())
|
||||||
|
throw index_error();
|
||||||
|
v.erase(v.begin() + i);
|
||||||
|
}, "erases element at index ``i``");
|
||||||
|
|
||||||
|
cl.def("empty", &Vector::empty, "checks whether the container is empty");
|
||||||
|
cl.def("size", &Vector::size, "returns the number of elements");
|
||||||
|
cl.def("push_back", (void (Vector::*)(const T&)) &Vector::push_back, "adds an element to the end");
|
||||||
|
cl.def("pop_back", &Vector::pop_back, "removes the last element");
|
||||||
|
|
||||||
|
cl.def("max_size", &Vector::max_size, "returns the maximum possible number of elements");
|
||||||
|
cl.def("reserve", &Vector::reserve, "reserves storage");
|
||||||
|
cl.def("capacity", &Vector::capacity, "returns the number of elements that can be held in currently allocated storage");
|
||||||
|
cl.def("shrink_to_fit", &Vector::shrink_to_fit, "reduces memory usage by freeing unused memory");
|
||||||
|
|
||||||
|
cl.def("clear", &Vector::clear, "clears the contents");
|
||||||
|
cl.def("swap", &Vector::swap, "swaps the contents");
|
||||||
|
|
||||||
|
cl.def("front", [](Vector &v) {
|
||||||
|
if (v.size()) return v.front();
|
||||||
|
else throw index_error();
|
||||||
|
}, "access the first element");
|
||||||
|
|
||||||
|
cl.def("back", [](Vector &v) {
|
||||||
|
if (v.size()) return v.back();
|
||||||
|
else throw index_error();
|
||||||
|
}, "access the last element ");
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return cl;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// std::map, std::unordered_map
|
||||||
|
//
|
||||||
|
|
||||||
|
NAMESPACE_BEGIN(detail)
|
||||||
|
|
||||||
|
/* Fallback functions */
|
||||||
|
template <typename, typename, typename... Args> void map_if_insertion_operator(const Args &...) { }
|
||||||
|
template <typename, typename, typename... Args> void map_assignment(const Args &...) { }
|
||||||
|
|
||||||
|
// Map assignment when copy-assignable: just copy the value
|
||||||
|
template <typename Map, typename Class_>
|
||||||
|
void map_assignment(enable_if_t<is_copy_assignable<typename Map::mapped_type>::value, Class_> &cl) {
|
||||||
|
using KeyType = typename Map::key_type;
|
||||||
|
using MappedType = typename Map::mapped_type;
|
||||||
|
|
||||||
|
cl.def("__setitem__",
|
||||||
|
[](Map &m, const KeyType &k, const MappedType &v) {
|
||||||
|
auto it = m.find(k);
|
||||||
|
if (it != m.end()) it->second = v;
|
||||||
|
else m.emplace(k, v);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Not copy-assignable, but still copy-constructible: we can update the value by erasing and reinserting
|
||||||
|
template<typename Map, typename Class_>
|
||||||
|
void map_assignment(enable_if_t<
|
||||||
|
!is_copy_assignable<typename Map::mapped_type>::value &&
|
||||||
|
is_copy_constructible<typename Map::mapped_type>::value,
|
||||||
|
Class_> &cl) {
|
||||||
|
using KeyType = typename Map::key_type;
|
||||||
|
using MappedType = typename Map::mapped_type;
|
||||||
|
|
||||||
|
cl.def("__setitem__",
|
||||||
|
[](Map &m, const KeyType &k, const MappedType &v) {
|
||||||
|
// We can't use m[k] = v; because value type might not be default constructable
|
||||||
|
auto r = m.emplace(k, v);
|
||||||
|
if (!r.second) {
|
||||||
|
// value type is not copy assignable so the only way to insert it is to erase it first...
|
||||||
|
m.erase(r.first);
|
||||||
|
m.emplace(k, v);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template <typename Map, typename Class_> auto map_if_insertion_operator(Class_ &cl, std::string const &name)
|
||||||
|
-> decltype(std::declval<std::ostream&>() << std::declval<typename Map::key_type>() << std::declval<typename Map::mapped_type>(), void()) {
|
||||||
|
|
||||||
|
cl.def("__repr__",
|
||||||
|
[name](Map &m) {
|
||||||
|
std::ostringstream s;
|
||||||
|
s << name << '{';
|
||||||
|
bool f = false;
|
||||||
|
for (auto const &kv : m) {
|
||||||
|
if (f)
|
||||||
|
s << ", ";
|
||||||
|
s << kv.first << ": " << kv.second;
|
||||||
|
f = true;
|
||||||
|
}
|
||||||
|
s << '}';
|
||||||
|
return s.str();
|
||||||
|
},
|
||||||
|
"Return the canonical string representation of this map."
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
NAMESPACE_END(detail)
|
||||||
|
|
||||||
|
template <typename Map, typename holder_type = std::unique_ptr<Map>, typename... Args>
|
||||||
|
class_<Map, holder_type> bind_map(handle scope, const std::string &name, Args&&... args) {
|
||||||
|
using KeyType = typename Map::key_type;
|
||||||
|
using MappedType = typename Map::mapped_type;
|
||||||
|
using Class_ = class_<Map, holder_type>;
|
||||||
|
|
||||||
|
// If either type is a non-module-local bound type then make the map binding non-local as well;
|
||||||
|
// otherwise (e.g. both types are either module-local or converting) the map will be
|
||||||
|
// module-local.
|
||||||
|
auto tinfo = detail::get_type_info(typeid(MappedType));
|
||||||
|
bool local = !tinfo || tinfo->module_local;
|
||||||
|
if (local) {
|
||||||
|
tinfo = detail::get_type_info(typeid(KeyType));
|
||||||
|
local = !tinfo || tinfo->module_local;
|
||||||
|
}
|
||||||
|
|
||||||
|
Class_ cl(scope, name.c_str(), pybind11::module_local(local), std::forward<Args>(args)...);
|
||||||
|
|
||||||
|
cl.def(init<>());
|
||||||
|
|
||||||
|
// Register stream insertion operator (if possible)
|
||||||
|
detail::map_if_insertion_operator<Map, Class_>(cl, name);
|
||||||
|
|
||||||
|
cl.def("__bool__",
|
||||||
|
[](const Map &m) -> bool { return !m.empty(); },
|
||||||
|
"Check whether the map is nonempty"
|
||||||
|
);
|
||||||
|
|
||||||
|
cl.def("__iter__",
|
||||||
|
[](Map &m) { return make_key_iterator(m.begin(), m.end()); },
|
||||||
|
keep_alive<0, 1>() /* Essential: keep list alive while iterator exists */
|
||||||
|
);
|
||||||
|
|
||||||
|
cl.def("items",
|
||||||
|
[](Map &m) { return make_iterator(m.begin(), m.end()); },
|
||||||
|
keep_alive<0, 1>() /* Essential: keep list alive while iterator exists */
|
||||||
|
);
|
||||||
|
|
||||||
|
cl.def("__getitem__",
|
||||||
|
[](Map &m, const KeyType &k) -> MappedType & {
|
||||||
|
auto it = m.find(k);
|
||||||
|
if (it == m.end())
|
||||||
|
throw key_error();
|
||||||
|
return it->second;
|
||||||
|
},
|
||||||
|
return_value_policy::reference_internal // ref + keepalive
|
||||||
|
);
|
||||||
|
|
||||||
|
cl.def("__contains__",
|
||||||
|
[](Map &m, const KeyType &k) -> bool {
|
||||||
|
auto it = m.find(k);
|
||||||
|
if (it == m.end())
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
// Assignment provided only if the type is copyable
|
||||||
|
detail::map_assignment<Map, Class_>(cl);
|
||||||
|
|
||||||
|
cl.def("__delitem__",
|
||||||
|
[](Map &m, const KeyType &k) {
|
||||||
|
auto it = m.find(k);
|
||||||
|
if (it == m.end())
|
||||||
|
throw key_error();
|
||||||
|
m.erase(it);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
cl.def("__len__", &Map::size);
|
||||||
|
|
||||||
|
return cl;
|
||||||
|
}
|
||||||
|
|
||||||
|
NAMESPACE_END(PYBIND11_NAMESPACE)
|
12
3rdparty/pybind11/pybind11/__init__.py
vendored
Normal file
12
3rdparty/pybind11/pybind11/__init__.py
vendored
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
from ._version import version_info, __version__ # noqa: F401 imported but unused
|
||||||
|
|
||||||
|
|
||||||
|
def get_include(user=False):
|
||||||
|
import os
|
||||||
|
d = os.path.dirname(__file__)
|
||||||
|
if os.path.exists(os.path.join(d, "include")):
|
||||||
|
# Package is installed
|
||||||
|
return os.path.join(d, "include")
|
||||||
|
else:
|
||||||
|
# Package is from a source directory
|
||||||
|
return os.path.join(os.path.dirname(d), "include")
|
36
3rdparty/pybind11/pybind11/__main__.py
vendored
Normal file
36
3rdparty/pybind11/pybind11/__main__.py
vendored
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
from __future__ import print_function
|
||||||
|
|
||||||
|
import argparse
|
||||||
|
import sys
|
||||||
|
import sysconfig
|
||||||
|
|
||||||
|
from . import get_include
|
||||||
|
|
||||||
|
|
||||||
|
def print_includes():
|
||||||
|
dirs = [sysconfig.get_path('include'),
|
||||||
|
sysconfig.get_path('platinclude'),
|
||||||
|
get_include()]
|
||||||
|
|
||||||
|
# Make unique but preserve order
|
||||||
|
unique_dirs = []
|
||||||
|
for d in dirs:
|
||||||
|
if d not in unique_dirs:
|
||||||
|
unique_dirs.append(d)
|
||||||
|
|
||||||
|
print(' '.join('-I' + d for d in unique_dirs))
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
parser = argparse.ArgumentParser(prog='python -m pybind11')
|
||||||
|
parser.add_argument('--includes', action='store_true',
|
||||||
|
help='Include flags for both pybind11 and Python headers.')
|
||||||
|
args = parser.parse_args()
|
||||||
|
if not sys.argv[1:]:
|
||||||
|
parser.print_help()
|
||||||
|
if args.includes:
|
||||||
|
print_includes()
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
2
3rdparty/pybind11/pybind11/_version.py
vendored
Normal file
2
3rdparty/pybind11/pybind11/_version.py
vendored
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
version_info = (2, 5, 0)
|
||||||
|
__version__ = '.'.join(map(str, version_info))
|
12
3rdparty/pybind11/setup.cfg
vendored
Normal file
12
3rdparty/pybind11/setup.cfg
vendored
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
[bdist_wheel]
|
||||||
|
universal=1
|
||||||
|
|
||||||
|
[flake8]
|
||||||
|
max-line-length = 99
|
||||||
|
show_source = True
|
||||||
|
exclude = .git, __pycache__, build, dist, docs, tools, venv
|
||||||
|
ignore =
|
||||||
|
# required for pretty matrix formatting: multiple spaces after `,` and `[`
|
||||||
|
E201, E241, W504,
|
||||||
|
# camelcase 'cPickle' imported as lowercase 'pickle'
|
||||||
|
N813
|
122
3rdparty/pybind11/setup.py
vendored
Normal file
122
3rdparty/pybind11/setup.py
vendored
Normal file
@ -0,0 +1,122 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
|
||||||
|
# Setup script for PyPI; use CMakeFile.txt to build extension modules
|
||||||
|
|
||||||
|
from setuptools import setup
|
||||||
|
from distutils.command.install_headers import install_headers
|
||||||
|
from distutils.command.build_py import build_py
|
||||||
|
from pybind11 import __version__
|
||||||
|
import os
|
||||||
|
|
||||||
|
package_data = [
|
||||||
|
'include/pybind11/detail/class.h',
|
||||||
|
'include/pybind11/detail/common.h',
|
||||||
|
'include/pybind11/detail/descr.h',
|
||||||
|
'include/pybind11/detail/init.h',
|
||||||
|
'include/pybind11/detail/internals.h',
|
||||||
|
'include/pybind11/detail/typeid.h',
|
||||||
|
'include/pybind11/attr.h',
|
||||||
|
'include/pybind11/buffer_info.h',
|
||||||
|
'include/pybind11/cast.h',
|
||||||
|
'include/pybind11/chrono.h',
|
||||||
|
'include/pybind11/common.h',
|
||||||
|
'include/pybind11/complex.h',
|
||||||
|
'include/pybind11/eigen.h',
|
||||||
|
'include/pybind11/embed.h',
|
||||||
|
'include/pybind11/eval.h',
|
||||||
|
'include/pybind11/functional.h',
|
||||||
|
'include/pybind11/iostream.h',
|
||||||
|
'include/pybind11/numpy.h',
|
||||||
|
'include/pybind11/operators.h',
|
||||||
|
'include/pybind11/options.h',
|
||||||
|
'include/pybind11/pybind11.h',
|
||||||
|
'include/pybind11/pytypes.h',
|
||||||
|
'include/pybind11/stl.h',
|
||||||
|
'include/pybind11/stl_bind.h',
|
||||||
|
]
|
||||||
|
|
||||||
|
# Prevent installation of pybind11 headers by setting
|
||||||
|
# PYBIND11_USE_CMAKE.
|
||||||
|
if os.environ.get('PYBIND11_USE_CMAKE'):
|
||||||
|
headers = []
|
||||||
|
else:
|
||||||
|
headers = package_data
|
||||||
|
|
||||||
|
|
||||||
|
class InstallHeaders(install_headers):
|
||||||
|
"""Use custom header installer because the default one flattens subdirectories"""
|
||||||
|
def run(self):
|
||||||
|
if not self.distribution.headers:
|
||||||
|
return
|
||||||
|
|
||||||
|
for header in self.distribution.headers:
|
||||||
|
subdir = os.path.dirname(os.path.relpath(header, 'include/pybind11'))
|
||||||
|
install_dir = os.path.join(self.install_dir, subdir)
|
||||||
|
self.mkpath(install_dir)
|
||||||
|
|
||||||
|
(out, _) = self.copy_file(header, install_dir)
|
||||||
|
self.outfiles.append(out)
|
||||||
|
|
||||||
|
|
||||||
|
# Install the headers inside the package as well
|
||||||
|
class BuildPy(build_py):
|
||||||
|
def build_package_data(self):
|
||||||
|
build_py.build_package_data(self)
|
||||||
|
for header in package_data:
|
||||||
|
target = os.path.join(self.build_lib, 'pybind11', header)
|
||||||
|
self.mkpath(os.path.dirname(target))
|
||||||
|
self.copy_file(header, target, preserve_mode=False)
|
||||||
|
|
||||||
|
|
||||||
|
setup(
|
||||||
|
name='pybind11',
|
||||||
|
version=__version__,
|
||||||
|
description='Seamless operability between C++11 and Python',
|
||||||
|
author='Wenzel Jakob',
|
||||||
|
author_email='wenzel.jakob@epfl.ch',
|
||||||
|
url='https://github.com/pybind/pybind11',
|
||||||
|
download_url='https://github.com/pybind/pybind11/tarball/v' + __version__,
|
||||||
|
packages=['pybind11'],
|
||||||
|
license='BSD',
|
||||||
|
headers=headers,
|
||||||
|
zip_safe=False,
|
||||||
|
cmdclass=dict(install_headers=InstallHeaders, build_py=BuildPy),
|
||||||
|
classifiers=[
|
||||||
|
'Development Status :: 5 - Production/Stable',
|
||||||
|
'Intended Audience :: Developers',
|
||||||
|
'Topic :: Software Development :: Libraries :: Python Modules',
|
||||||
|
'Topic :: Utilities',
|
||||||
|
'Programming Language :: C++',
|
||||||
|
'Programming Language :: Python :: 2.7',
|
||||||
|
'Programming Language :: Python :: 3',
|
||||||
|
'Programming Language :: Python :: 3.2',
|
||||||
|
'Programming Language :: Python :: 3.3',
|
||||||
|
'Programming Language :: Python :: 3.4',
|
||||||
|
'Programming Language :: Python :: 3.5',
|
||||||
|
'Programming Language :: Python :: 3.6',
|
||||||
|
'License :: OSI Approved :: BSD License'
|
||||||
|
],
|
||||||
|
keywords='C++11, Python bindings',
|
||||||
|
long_description="""pybind11 is a lightweight header-only library that
|
||||||
|
exposes C++ types in Python and vice versa, mainly to create Python bindings of
|
||||||
|
existing C++ code. Its goals and syntax are similar to the excellent
|
||||||
|
Boost.Python by David Abrahams: to minimize boilerplate code in traditional
|
||||||
|
extension modules by inferring type information using compile-time
|
||||||
|
introspection.
|
||||||
|
|
||||||
|
The main issue with Boost.Python-and the reason for creating such a similar
|
||||||
|
project-is Boost. Boost is an enormously large and complex suite of utility
|
||||||
|
libraries that works with almost every C++ compiler in existence. This
|
||||||
|
compatibility has its cost: arcane template tricks and workarounds are
|
||||||
|
necessary to support the oldest and buggiest of compiler specimens. Now that
|
||||||
|
C++11-compatible compilers are widely available, this heavy machinery has
|
||||||
|
become an excessively large and unnecessary dependency.
|
||||||
|
|
||||||
|
Think of this library as a tiny self-contained version of Boost.Python with
|
||||||
|
everything stripped away that isn't relevant for binding generation. Without
|
||||||
|
comments, the core header files only require ~4K lines of code and depend on
|
||||||
|
Python (2.7 or 3.x, or PyPy2.7 >= 5.7) and the C++ standard library. This
|
||||||
|
compact implementation was possible thanks to some of the new C++11 language
|
||||||
|
features (specifically: tuples, lambda functions and variadic templates). Since
|
||||||
|
its creation, this library has grown beyond Boost.Python in many ways, leading
|
||||||
|
to dramatically simpler binding code in many common situations.""")
|
259
3rdparty/pybind11/tests/CMakeLists.txt
vendored
Normal file
259
3rdparty/pybind11/tests/CMakeLists.txt
vendored
Normal file
@ -0,0 +1,259 @@
|
|||||||
|
# CMakeLists.txt -- Build system for the pybind11 test suite
|
||||||
|
#
|
||||||
|
# Copyright (c) 2015 Wenzel Jakob <wenzel@inf.ethz.ch>
|
||||||
|
#
|
||||||
|
# All rights reserved. Use of this source code is governed by a
|
||||||
|
# BSD-style license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
cmake_minimum_required(VERSION 2.8.12)
|
||||||
|
|
||||||
|
option(PYBIND11_WERROR "Report all warnings as errors" OFF)
|
||||||
|
|
||||||
|
if (CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_SOURCE_DIR)
|
||||||
|
# We're being loaded directly, i.e. not via add_subdirectory, so make this
|
||||||
|
# work as its own project and load the pybind11Config to get the tools we need
|
||||||
|
project(pybind11_tests CXX)
|
||||||
|
|
||||||
|
find_package(pybind11 REQUIRED CONFIG)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
|
||||||
|
message(STATUS "Setting tests build type to MinSizeRel as none was specified")
|
||||||
|
set(CMAKE_BUILD_TYPE MinSizeRel CACHE STRING "Choose the type of build." FORCE)
|
||||||
|
set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS "Debug" "Release"
|
||||||
|
"MinSizeRel" "RelWithDebInfo")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Full set of test files (you can override these; see below)
|
||||||
|
set(PYBIND11_TEST_FILES
|
||||||
|
test_async.cpp
|
||||||
|
test_buffers.cpp
|
||||||
|
test_builtin_casters.cpp
|
||||||
|
test_call_policies.cpp
|
||||||
|
test_callbacks.cpp
|
||||||
|
test_chrono.cpp
|
||||||
|
test_class.cpp
|
||||||
|
test_constants_and_functions.cpp
|
||||||
|
test_copy_move.cpp
|
||||||
|
test_docstring_options.cpp
|
||||||
|
test_eigen.cpp
|
||||||
|
test_enum.cpp
|
||||||
|
test_eval.cpp
|
||||||
|
test_exceptions.cpp
|
||||||
|
test_factory_constructors.cpp
|
||||||
|
test_gil_scoped.cpp
|
||||||
|
test_iostream.cpp
|
||||||
|
test_kwargs_and_defaults.cpp
|
||||||
|
test_local_bindings.cpp
|
||||||
|
test_methods_and_attributes.cpp
|
||||||
|
test_modules.cpp
|
||||||
|
test_multiple_inheritance.cpp
|
||||||
|
test_numpy_array.cpp
|
||||||
|
test_numpy_dtypes.cpp
|
||||||
|
test_numpy_vectorize.cpp
|
||||||
|
test_opaque_types.cpp
|
||||||
|
test_operator_overloading.cpp
|
||||||
|
test_pickling.cpp
|
||||||
|
test_pytypes.cpp
|
||||||
|
test_sequences_and_iterators.cpp
|
||||||
|
test_smart_ptr.cpp
|
||||||
|
test_stl.cpp
|
||||||
|
test_stl_binders.cpp
|
||||||
|
test_tagbased_polymorphic.cpp
|
||||||
|
test_union.cpp
|
||||||
|
test_virtual_functions.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
# Invoking cmake with something like:
|
||||||
|
# cmake -DPYBIND11_TEST_OVERRIDE="test_callbacks.cpp;test_picking.cpp" ..
|
||||||
|
# lets you override the tests that get compiled and run. You can restore to all tests with:
|
||||||
|
# cmake -DPYBIND11_TEST_OVERRIDE= ..
|
||||||
|
if (PYBIND11_TEST_OVERRIDE)
|
||||||
|
set(PYBIND11_TEST_FILES ${PYBIND11_TEST_OVERRIDE})
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Skip test_async for Python < 3.5
|
||||||
|
list(FIND PYBIND11_TEST_FILES test_async.cpp PYBIND11_TEST_FILES_ASYNC_I)
|
||||||
|
if((PYBIND11_TEST_FILES_ASYNC_I GREATER -1) AND ("${PYTHON_VERSION_MAJOR}.${PYTHON_VERSION_MINOR}" VERSION_LESS 3.5))
|
||||||
|
message(STATUS "Skipping test_async because Python version ${PYTHON_VERSION_MAJOR}.${PYTHON_VERSION_MINOR} < 3.5")
|
||||||
|
list(REMOVE_AT PYBIND11_TEST_FILES ${PYBIND11_TEST_FILES_ASYNC_I})
|
||||||
|
endif()
|
||||||
|
|
||||||
|
string(REPLACE ".cpp" ".py" PYBIND11_PYTEST_FILES "${PYBIND11_TEST_FILES}")
|
||||||
|
|
||||||
|
# Contains the set of test files that require pybind11_cross_module_tests to be
|
||||||
|
# built; if none of these are built (i.e. because TEST_OVERRIDE is used and
|
||||||
|
# doesn't include them) the second module doesn't get built.
|
||||||
|
set(PYBIND11_CROSS_MODULE_TESTS
|
||||||
|
test_exceptions.py
|
||||||
|
test_local_bindings.py
|
||||||
|
test_stl.py
|
||||||
|
test_stl_binders.py
|
||||||
|
)
|
||||||
|
|
||||||
|
set(PYBIND11_CROSS_MODULE_GIL_TESTS
|
||||||
|
test_gil_scoped.py
|
||||||
|
)
|
||||||
|
|
||||||
|
# Check if Eigen is available; if not, remove from PYBIND11_TEST_FILES (but
|
||||||
|
# keep it in PYBIND11_PYTEST_FILES, so that we get the "eigen is not installed"
|
||||||
|
# skip message).
|
||||||
|
list(FIND PYBIND11_TEST_FILES test_eigen.cpp PYBIND11_TEST_FILES_EIGEN_I)
|
||||||
|
if(PYBIND11_TEST_FILES_EIGEN_I GREATER -1)
|
||||||
|
# Try loading via newer Eigen's Eigen3Config first (bypassing tools/FindEigen3.cmake).
|
||||||
|
# Eigen 3.3.1+ exports a cmake 3.0+ target for handling dependency requirements, but also
|
||||||
|
# produces a fatal error if loaded from a pre-3.0 cmake.
|
||||||
|
if (NOT CMAKE_VERSION VERSION_LESS 3.0)
|
||||||
|
find_package(Eigen3 3.2.7 QUIET CONFIG)
|
||||||
|
if (EIGEN3_FOUND)
|
||||||
|
if (EIGEN3_VERSION_STRING AND NOT EIGEN3_VERSION_STRING VERSION_LESS 3.3.1)
|
||||||
|
set(PYBIND11_EIGEN_VIA_TARGET 1)
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
if (NOT EIGEN3_FOUND)
|
||||||
|
# Couldn't load via target, so fall back to allowing module mode finding, which will pick up
|
||||||
|
# tools/FindEigen3.cmake
|
||||||
|
find_package(Eigen3 3.2.7 QUIET)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(EIGEN3_FOUND)
|
||||||
|
# Eigen 3.3.1+ cmake sets EIGEN3_VERSION_STRING (and hard codes the version when installed
|
||||||
|
# rather than looking it up in the cmake script); older versions, and the
|
||||||
|
# tools/FindEigen3.cmake, set EIGEN3_VERSION instead.
|
||||||
|
if(NOT EIGEN3_VERSION AND EIGEN3_VERSION_STRING)
|
||||||
|
set(EIGEN3_VERSION ${EIGEN3_VERSION_STRING})
|
||||||
|
endif()
|
||||||
|
message(STATUS "Building tests with Eigen v${EIGEN3_VERSION}")
|
||||||
|
else()
|
||||||
|
list(REMOVE_AT PYBIND11_TEST_FILES ${PYBIND11_TEST_FILES_EIGEN_I})
|
||||||
|
message(STATUS "Building tests WITHOUT Eigen")
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Optional dependency for some tests (boost::variant is only supported with version >= 1.56)
|
||||||
|
find_package(Boost 1.56)
|
||||||
|
|
||||||
|
# Compile with compiler warnings turned on
|
||||||
|
function(pybind11_enable_warnings target_name)
|
||||||
|
if(MSVC)
|
||||||
|
target_compile_options(${target_name} PRIVATE /W4)
|
||||||
|
elseif(CMAKE_CXX_COMPILER_ID MATCHES "(GNU|Intel|Clang)")
|
||||||
|
target_compile_options(${target_name} PRIVATE -Wall -Wextra -Wconversion -Wcast-qual -Wdeprecated)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(PYBIND11_WERROR)
|
||||||
|
if(MSVC)
|
||||||
|
target_compile_options(${target_name} PRIVATE /WX)
|
||||||
|
elseif(CMAKE_CXX_COMPILER_ID MATCHES "(GNU|Intel|Clang)")
|
||||||
|
target_compile_options(${target_name} PRIVATE -Werror)
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
endfunction()
|
||||||
|
|
||||||
|
set(test_targets pybind11_tests)
|
||||||
|
|
||||||
|
# Build pybind11_cross_module_tests if any test_whatever.py are being built that require it
|
||||||
|
foreach(t ${PYBIND11_CROSS_MODULE_TESTS})
|
||||||
|
list(FIND PYBIND11_PYTEST_FILES ${t} i)
|
||||||
|
if (i GREATER -1)
|
||||||
|
list(APPEND test_targets pybind11_cross_module_tests)
|
||||||
|
break()
|
||||||
|
endif()
|
||||||
|
endforeach()
|
||||||
|
|
||||||
|
foreach(t ${PYBIND11_CROSS_MODULE_GIL_TESTS})
|
||||||
|
list(FIND PYBIND11_PYTEST_FILES ${t} i)
|
||||||
|
if (i GREATER -1)
|
||||||
|
list(APPEND test_targets cross_module_gil_utils)
|
||||||
|
break()
|
||||||
|
endif()
|
||||||
|
endforeach()
|
||||||
|
|
||||||
|
set(testdir ${CMAKE_CURRENT_SOURCE_DIR})
|
||||||
|
foreach(target ${test_targets})
|
||||||
|
set(test_files ${PYBIND11_TEST_FILES})
|
||||||
|
if(NOT target STREQUAL "pybind11_tests")
|
||||||
|
set(test_files "")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Create the binding library
|
||||||
|
pybind11_add_module(${target} THIN_LTO ${target}.cpp ${test_files} ${PYBIND11_HEADERS})
|
||||||
|
pybind11_enable_warnings(${target})
|
||||||
|
|
||||||
|
if(MSVC)
|
||||||
|
target_compile_options(${target} PRIVATE /utf-8)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(EIGEN3_FOUND)
|
||||||
|
if (PYBIND11_EIGEN_VIA_TARGET)
|
||||||
|
target_link_libraries(${target} PRIVATE Eigen3::Eigen)
|
||||||
|
else()
|
||||||
|
target_include_directories(${target} PRIVATE ${EIGEN3_INCLUDE_DIR})
|
||||||
|
endif()
|
||||||
|
target_compile_definitions(${target} PRIVATE -DPYBIND11_TEST_EIGEN)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(Boost_FOUND)
|
||||||
|
target_include_directories(${target} PRIVATE ${Boost_INCLUDE_DIRS})
|
||||||
|
target_compile_definitions(${target} PRIVATE -DPYBIND11_TEST_BOOST)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Always write the output file directly into the 'tests' directory (even on MSVC)
|
||||||
|
if(NOT CMAKE_LIBRARY_OUTPUT_DIRECTORY)
|
||||||
|
set_target_properties(${target} PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${testdir})
|
||||||
|
foreach(config ${CMAKE_CONFIGURATION_TYPES})
|
||||||
|
string(TOUPPER ${config} config)
|
||||||
|
set_target_properties(${target} PROPERTIES LIBRARY_OUTPUT_DIRECTORY_${config} ${testdir})
|
||||||
|
endforeach()
|
||||||
|
endif()
|
||||||
|
endforeach()
|
||||||
|
|
||||||
|
# Make sure pytest is found or produce a fatal error
|
||||||
|
if(NOT PYBIND11_PYTEST_FOUND)
|
||||||
|
execute_process(COMMAND ${PYTHON_EXECUTABLE} -c "import pytest; print(pytest.__version__)"
|
||||||
|
RESULT_VARIABLE pytest_not_found OUTPUT_VARIABLE pytest_version ERROR_QUIET)
|
||||||
|
if(pytest_not_found)
|
||||||
|
message(FATAL_ERROR "Running the tests requires pytest. Please install it manually"
|
||||||
|
" (try: ${PYTHON_EXECUTABLE} -m pip install pytest)")
|
||||||
|
elseif(pytest_version VERSION_LESS 3.0)
|
||||||
|
message(FATAL_ERROR "Running the tests requires pytest >= 3.0. Found: ${pytest_version}"
|
||||||
|
"Please update it (try: ${PYTHON_EXECUTABLE} -m pip install -U pytest)")
|
||||||
|
endif()
|
||||||
|
set(PYBIND11_PYTEST_FOUND TRUE CACHE INTERNAL "")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(CMAKE_VERSION VERSION_LESS 3.2)
|
||||||
|
set(PYBIND11_USES_TERMINAL "")
|
||||||
|
else()
|
||||||
|
set(PYBIND11_USES_TERMINAL "USES_TERMINAL")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# A single command to compile and run the tests
|
||||||
|
add_custom_target(pytest COMMAND ${PYTHON_EXECUTABLE} -m pytest ${PYBIND11_PYTEST_FILES}
|
||||||
|
DEPENDS ${test_targets} WORKING_DIRECTORY ${testdir} ${PYBIND11_USES_TERMINAL})
|
||||||
|
|
||||||
|
if(PYBIND11_TEST_OVERRIDE)
|
||||||
|
add_custom_command(TARGET pytest POST_BUILD
|
||||||
|
COMMAND ${CMAKE_COMMAND} -E echo "Note: not all tests run: -DPYBIND11_TEST_OVERRIDE is in effect")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Add a check target to run all the tests, starting with pytest (we add dependencies to this below)
|
||||||
|
add_custom_target(check DEPENDS pytest)
|
||||||
|
|
||||||
|
# The remaining tests only apply when being built as part of the pybind11 project, but not if the
|
||||||
|
# tests are being built independently.
|
||||||
|
if (NOT PROJECT_NAME STREQUAL "pybind11")
|
||||||
|
return()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Add a post-build comment to show the primary test suite .so size and, if a previous size, compare it:
|
||||||
|
add_custom_command(TARGET pybind11_tests POST_BUILD
|
||||||
|
COMMAND ${PYTHON_EXECUTABLE} ${PROJECT_SOURCE_DIR}/tools/libsize.py
|
||||||
|
$<TARGET_FILE:pybind11_tests> ${CMAKE_CURRENT_BINARY_DIR}/sosize-$<TARGET_FILE_NAME:pybind11_tests>.txt)
|
||||||
|
|
||||||
|
# Test embedding the interpreter. Provides the `cpptest` target.
|
||||||
|
add_subdirectory(test_embed)
|
||||||
|
|
||||||
|
# Test CMake build using functions and targets from subdirectory or installed location
|
||||||
|
add_subdirectory(test_cmake_build)
|
244
3rdparty/pybind11/tests/conftest.py
vendored
Normal file
244
3rdparty/pybind11/tests/conftest.py
vendored
Normal file
@ -0,0 +1,244 @@
|
|||||||
|
"""pytest configuration
|
||||||
|
|
||||||
|
Extends output capture as needed by pybind11: ignore constructors, optional unordered lines.
|
||||||
|
Adds docstring and exceptions message sanitizers: ignore Python 2 vs 3 differences.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
import textwrap
|
||||||
|
import difflib
|
||||||
|
import re
|
||||||
|
import sys
|
||||||
|
import contextlib
|
||||||
|
import platform
|
||||||
|
import gc
|
||||||
|
|
||||||
|
_unicode_marker = re.compile(r'u(\'[^\']*\')')
|
||||||
|
_long_marker = re.compile(r'([0-9])L')
|
||||||
|
_hexadecimal = re.compile(r'0x[0-9a-fA-F]+')
|
||||||
|
|
||||||
|
# test_async.py requires support for async and await
|
||||||
|
collect_ignore = []
|
||||||
|
if sys.version_info[:2] < (3, 5):
|
||||||
|
collect_ignore.append("test_async.py")
|
||||||
|
|
||||||
|
|
||||||
|
def _strip_and_dedent(s):
|
||||||
|
"""For triple-quote strings"""
|
||||||
|
return textwrap.dedent(s.lstrip('\n').rstrip())
|
||||||
|
|
||||||
|
|
||||||
|
def _split_and_sort(s):
|
||||||
|
"""For output which does not require specific line order"""
|
||||||
|
return sorted(_strip_and_dedent(s).splitlines())
|
||||||
|
|
||||||
|
|
||||||
|
def _make_explanation(a, b):
|
||||||
|
"""Explanation for a failed assert -- the a and b arguments are List[str]"""
|
||||||
|
return ["--- actual / +++ expected"] + [line.strip('\n') for line in difflib.ndiff(a, b)]
|
||||||
|
|
||||||
|
|
||||||
|
class Output(object):
|
||||||
|
"""Basic output post-processing and comparison"""
|
||||||
|
def __init__(self, string):
|
||||||
|
self.string = string
|
||||||
|
self.explanation = []
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return self.string
|
||||||
|
|
||||||
|
def __eq__(self, other):
|
||||||
|
# Ignore constructor/destructor output which is prefixed with "###"
|
||||||
|
a = [line for line in self.string.strip().splitlines() if not line.startswith("###")]
|
||||||
|
b = _strip_and_dedent(other).splitlines()
|
||||||
|
if a == b:
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
self.explanation = _make_explanation(a, b)
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
class Unordered(Output):
|
||||||
|
"""Custom comparison for output without strict line ordering"""
|
||||||
|
def __eq__(self, other):
|
||||||
|
a = _split_and_sort(self.string)
|
||||||
|
b = _split_and_sort(other)
|
||||||
|
if a == b:
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
self.explanation = _make_explanation(a, b)
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
class Capture(object):
|
||||||
|
def __init__(self, capfd):
|
||||||
|
self.capfd = capfd
|
||||||
|
self.out = ""
|
||||||
|
self.err = ""
|
||||||
|
|
||||||
|
def __enter__(self):
|
||||||
|
self.capfd.readouterr()
|
||||||
|
return self
|
||||||
|
|
||||||
|
def __exit__(self, *args):
|
||||||
|
self.out, self.err = self.capfd.readouterr()
|
||||||
|
|
||||||
|
def __eq__(self, other):
|
||||||
|
a = Output(self.out)
|
||||||
|
b = other
|
||||||
|
if a == b:
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
self.explanation = a.explanation
|
||||||
|
return False
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return self.out
|
||||||
|
|
||||||
|
def __contains__(self, item):
|
||||||
|
return item in self.out
|
||||||
|
|
||||||
|
@property
|
||||||
|
def unordered(self):
|
||||||
|
return Unordered(self.out)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def stderr(self):
|
||||||
|
return Output(self.err)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def capture(capsys):
|
||||||
|
"""Extended `capsys` with context manager and custom equality operators"""
|
||||||
|
return Capture(capsys)
|
||||||
|
|
||||||
|
|
||||||
|
class SanitizedString(object):
|
||||||
|
def __init__(self, sanitizer):
|
||||||
|
self.sanitizer = sanitizer
|
||||||
|
self.string = ""
|
||||||
|
self.explanation = []
|
||||||
|
|
||||||
|
def __call__(self, thing):
|
||||||
|
self.string = self.sanitizer(thing)
|
||||||
|
return self
|
||||||
|
|
||||||
|
def __eq__(self, other):
|
||||||
|
a = self.string
|
||||||
|
b = _strip_and_dedent(other)
|
||||||
|
if a == b:
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
self.explanation = _make_explanation(a.splitlines(), b.splitlines())
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def _sanitize_general(s):
|
||||||
|
s = s.strip()
|
||||||
|
s = s.replace("pybind11_tests.", "m.")
|
||||||
|
s = s.replace("unicode", "str")
|
||||||
|
s = _long_marker.sub(r"\1", s)
|
||||||
|
s = _unicode_marker.sub(r"\1", s)
|
||||||
|
return s
|
||||||
|
|
||||||
|
|
||||||
|
def _sanitize_docstring(thing):
|
||||||
|
s = thing.__doc__
|
||||||
|
s = _sanitize_general(s)
|
||||||
|
return s
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def doc():
|
||||||
|
"""Sanitize docstrings and add custom failure explanation"""
|
||||||
|
return SanitizedString(_sanitize_docstring)
|
||||||
|
|
||||||
|
|
||||||
|
def _sanitize_message(thing):
|
||||||
|
s = str(thing)
|
||||||
|
s = _sanitize_general(s)
|
||||||
|
s = _hexadecimal.sub("0", s)
|
||||||
|
return s
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def msg():
|
||||||
|
"""Sanitize messages and add custom failure explanation"""
|
||||||
|
return SanitizedString(_sanitize_message)
|
||||||
|
|
||||||
|
|
||||||
|
# noinspection PyUnusedLocal
|
||||||
|
def pytest_assertrepr_compare(op, left, right):
|
||||||
|
"""Hook to insert custom failure explanation"""
|
||||||
|
if hasattr(left, 'explanation'):
|
||||||
|
return left.explanation
|
||||||
|
|
||||||
|
|
||||||
|
@contextlib.contextmanager
|
||||||
|
def suppress(exception):
|
||||||
|
"""Suppress the desired exception"""
|
||||||
|
try:
|
||||||
|
yield
|
||||||
|
except exception:
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def gc_collect():
|
||||||
|
''' Run the garbage collector twice (needed when running
|
||||||
|
reference counting tests with PyPy) '''
|
||||||
|
gc.collect()
|
||||||
|
gc.collect()
|
||||||
|
|
||||||
|
|
||||||
|
def pytest_configure():
|
||||||
|
"""Add import suppression and test requirements to `pytest` namespace"""
|
||||||
|
try:
|
||||||
|
import numpy as np
|
||||||
|
except ImportError:
|
||||||
|
np = None
|
||||||
|
try:
|
||||||
|
import scipy
|
||||||
|
except ImportError:
|
||||||
|
scipy = None
|
||||||
|
try:
|
||||||
|
from pybind11_tests.eigen import have_eigen
|
||||||
|
except ImportError:
|
||||||
|
have_eigen = False
|
||||||
|
pypy = platform.python_implementation() == "PyPy"
|
||||||
|
|
||||||
|
skipif = pytest.mark.skipif
|
||||||
|
pytest.suppress = suppress
|
||||||
|
pytest.requires_numpy = skipif(not np, reason="numpy is not installed")
|
||||||
|
pytest.requires_scipy = skipif(not np, reason="scipy is not installed")
|
||||||
|
pytest.requires_eigen_and_numpy = skipif(not have_eigen or not np,
|
||||||
|
reason="eigen and/or numpy are not installed")
|
||||||
|
pytest.requires_eigen_and_scipy = skipif(
|
||||||
|
not have_eigen or not scipy, reason="eigen and/or scipy are not installed")
|
||||||
|
pytest.unsupported_on_pypy = skipif(pypy, reason="unsupported on PyPy")
|
||||||
|
pytest.unsupported_on_py2 = skipif(sys.version_info.major < 3,
|
||||||
|
reason="unsupported on Python 2.x")
|
||||||
|
pytest.gc_collect = gc_collect
|
||||||
|
|
||||||
|
|
||||||
|
def _test_import_pybind11():
|
||||||
|
"""Early diagnostic for test module initialization errors
|
||||||
|
|
||||||
|
When there is an error during initialization, the first import will report the
|
||||||
|
real error while all subsequent imports will report nonsense. This import test
|
||||||
|
is done early (in the pytest configuration file, before any tests) in order to
|
||||||
|
avoid the noise of having all tests fail with identical error messages.
|
||||||
|
|
||||||
|
Any possible exception is caught here and reported manually *without* the stack
|
||||||
|
trace. This further reduces noise since the trace would only show pytest internals
|
||||||
|
which are not useful for debugging pybind11 module issues.
|
||||||
|
"""
|
||||||
|
# noinspection PyBroadException
|
||||||
|
try:
|
||||||
|
import pybind11_tests # noqa: F401 imported but unused
|
||||||
|
except Exception as e:
|
||||||
|
print("Failed to import pybind11_tests from pytest:")
|
||||||
|
print(" {}: {}".format(type(e).__name__, e))
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
|
||||||
|
_test_import_pybind11()
|
276
3rdparty/pybind11/tests/constructor_stats.h
vendored
Normal file
276
3rdparty/pybind11/tests/constructor_stats.h
vendored
Normal file
@ -0,0 +1,276 @@
|
|||||||
|
#pragma once
|
||||||
|
/*
|
||||||
|
tests/constructor_stats.h -- framework for printing and tracking object
|
||||||
|
instance lifetimes in example/test code.
|
||||||
|
|
||||||
|
Copyright (c) 2016 Jason Rhinelander <jason@imaginary.ca>
|
||||||
|
|
||||||
|
All rights reserved. Use of this source code is governed by a
|
||||||
|
BSD-style license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
This header provides a few useful tools for writing examples or tests that want to check and/or
|
||||||
|
display object instance lifetimes. It requires that you include this header and add the following
|
||||||
|
function calls to constructors:
|
||||||
|
|
||||||
|
class MyClass {
|
||||||
|
MyClass() { ...; print_default_created(this); }
|
||||||
|
~MyClass() { ...; print_destroyed(this); }
|
||||||
|
MyClass(const MyClass &c) { ...; print_copy_created(this); }
|
||||||
|
MyClass(MyClass &&c) { ...; print_move_created(this); }
|
||||||
|
MyClass(int a, int b) { ...; print_created(this, a, b); }
|
||||||
|
MyClass &operator=(const MyClass &c) { ...; print_copy_assigned(this); }
|
||||||
|
MyClass &operator=(MyClass &&c) { ...; print_move_assigned(this); }
|
||||||
|
|
||||||
|
...
|
||||||
|
}
|
||||||
|
|
||||||
|
You can find various examples of these in several of the existing testing .cpp files. (Of course
|
||||||
|
you don't need to add any of the above constructors/operators that you don't actually have, except
|
||||||
|
for the destructor).
|
||||||
|
|
||||||
|
Each of these will print an appropriate message such as:
|
||||||
|
|
||||||
|
### MyClass @ 0x2801910 created via default constructor
|
||||||
|
### MyClass @ 0x27fa780 created 100 200
|
||||||
|
### MyClass @ 0x2801910 destroyed
|
||||||
|
### MyClass @ 0x27fa780 destroyed
|
||||||
|
|
||||||
|
You can also include extra arguments (such as the 100, 200 in the output above, coming from the
|
||||||
|
value constructor) for all of the above methods which will be included in the output.
|
||||||
|
|
||||||
|
For testing, each of these also keeps track the created instances and allows you to check how many
|
||||||
|
of the various constructors have been invoked from the Python side via code such as:
|
||||||
|
|
||||||
|
from pybind11_tests import ConstructorStats
|
||||||
|
cstats = ConstructorStats.get(MyClass)
|
||||||
|
print(cstats.alive())
|
||||||
|
print(cstats.default_constructions)
|
||||||
|
|
||||||
|
Note that `.alive()` should usually be the first thing you call as it invokes Python's garbage
|
||||||
|
collector to actually destroy objects that aren't yet referenced.
|
||||||
|
|
||||||
|
For everything except copy and move constructors and destructors, any extra values given to the
|
||||||
|
print_...() function is stored in a class-specific values list which you can retrieve and inspect
|
||||||
|
from the ConstructorStats instance `.values()` method.
|
||||||
|
|
||||||
|
In some cases, when you need to track instances of a C++ class not registered with pybind11, you
|
||||||
|
need to add a function returning the ConstructorStats for the C++ class; this can be done with:
|
||||||
|
|
||||||
|
m.def("get_special_cstats", &ConstructorStats::get<SpecialClass>, py::return_value_policy::reference)
|
||||||
|
|
||||||
|
Finally, you can suppress the output messages, but keep the constructor tracking (for
|
||||||
|
inspection/testing in python) by using the functions with `print_` replaced with `track_` (e.g.
|
||||||
|
`track_copy_created(this)`).
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "pybind11_tests.h"
|
||||||
|
#include <unordered_map>
|
||||||
|
#include <list>
|
||||||
|
#include <typeindex>
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
|
class ConstructorStats {
|
||||||
|
protected:
|
||||||
|
std::unordered_map<void*, int> _instances; // Need a map rather than set because members can shared address with parents
|
||||||
|
std::list<std::string> _values; // Used to track values (e.g. of value constructors)
|
||||||
|
public:
|
||||||
|
int default_constructions = 0;
|
||||||
|
int copy_constructions = 0;
|
||||||
|
int move_constructions = 0;
|
||||||
|
int copy_assignments = 0;
|
||||||
|
int move_assignments = 0;
|
||||||
|
|
||||||
|
void copy_created(void *inst) {
|
||||||
|
created(inst);
|
||||||
|
copy_constructions++;
|
||||||
|
}
|
||||||
|
|
||||||
|
void move_created(void *inst) {
|
||||||
|
created(inst);
|
||||||
|
move_constructions++;
|
||||||
|
}
|
||||||
|
|
||||||
|
void default_created(void *inst) {
|
||||||
|
created(inst);
|
||||||
|
default_constructions++;
|
||||||
|
}
|
||||||
|
|
||||||
|
void created(void *inst) {
|
||||||
|
++_instances[inst];
|
||||||
|
}
|
||||||
|
|
||||||
|
void destroyed(void *inst) {
|
||||||
|
if (--_instances[inst] < 0)
|
||||||
|
throw std::runtime_error("cstats.destroyed() called with unknown "
|
||||||
|
"instance; potential double-destruction "
|
||||||
|
"or a missing cstats.created()");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void gc() {
|
||||||
|
// Force garbage collection to ensure any pending destructors are invoked:
|
||||||
|
#if defined(PYPY_VERSION)
|
||||||
|
PyObject *globals = PyEval_GetGlobals();
|
||||||
|
PyObject *result = PyRun_String(
|
||||||
|
"import gc\n"
|
||||||
|
"for i in range(2):"
|
||||||
|
" gc.collect()\n",
|
||||||
|
Py_file_input, globals, globals);
|
||||||
|
if (result == nullptr)
|
||||||
|
throw py::error_already_set();
|
||||||
|
Py_DECREF(result);
|
||||||
|
#else
|
||||||
|
py::module::import("gc").attr("collect")();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
int alive() {
|
||||||
|
gc();
|
||||||
|
int total = 0;
|
||||||
|
for (const auto &p : _instances)
|
||||||
|
if (p.second > 0)
|
||||||
|
total += p.second;
|
||||||
|
return total;
|
||||||
|
}
|
||||||
|
|
||||||
|
void value() {} // Recursion terminator
|
||||||
|
// Takes one or more values, converts them to strings, then stores them.
|
||||||
|
template <typename T, typename... Tmore> void value(const T &v, Tmore &&...args) {
|
||||||
|
std::ostringstream oss;
|
||||||
|
oss << v;
|
||||||
|
_values.push_back(oss.str());
|
||||||
|
value(std::forward<Tmore>(args)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Move out stored values
|
||||||
|
py::list values() {
|
||||||
|
py::list l;
|
||||||
|
for (const auto &v : _values) l.append(py::cast(v));
|
||||||
|
_values.clear();
|
||||||
|
return l;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Gets constructor stats from a C++ type index
|
||||||
|
static ConstructorStats& get(std::type_index type) {
|
||||||
|
static std::unordered_map<std::type_index, ConstructorStats> all_cstats;
|
||||||
|
return all_cstats[type];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Gets constructor stats from a C++ type
|
||||||
|
template <typename T> static ConstructorStats& get() {
|
||||||
|
#if defined(PYPY_VERSION)
|
||||||
|
gc();
|
||||||
|
#endif
|
||||||
|
return get(typeid(T));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Gets constructor stats from a Python class
|
||||||
|
static ConstructorStats& get(py::object class_) {
|
||||||
|
auto &internals = py::detail::get_internals();
|
||||||
|
const std::type_index *t1 = nullptr, *t2 = nullptr;
|
||||||
|
try {
|
||||||
|
auto *type_info = internals.registered_types_py.at((PyTypeObject *) class_.ptr()).at(0);
|
||||||
|
for (auto &p : internals.registered_types_cpp) {
|
||||||
|
if (p.second == type_info) {
|
||||||
|
if (t1) {
|
||||||
|
t2 = &p.first;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
t1 = &p.first;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (const std::out_of_range&) {}
|
||||||
|
if (!t1) throw std::runtime_error("Unknown class passed to ConstructorStats::get()");
|
||||||
|
auto &cs1 = get(*t1);
|
||||||
|
// If we have both a t1 and t2 match, one is probably the trampoline class; return whichever
|
||||||
|
// has more constructions (typically one or the other will be 0)
|
||||||
|
if (t2) {
|
||||||
|
auto &cs2 = get(*t2);
|
||||||
|
int cs1_total = cs1.default_constructions + cs1.copy_constructions + cs1.move_constructions + (int) cs1._values.size();
|
||||||
|
int cs2_total = cs2.default_constructions + cs2.copy_constructions + cs2.move_constructions + (int) cs2._values.size();
|
||||||
|
if (cs2_total > cs1_total) return cs2;
|
||||||
|
}
|
||||||
|
return cs1;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// To track construction/destruction, you need to call these methods from the various
|
||||||
|
// constructors/operators. The ones that take extra values record the given values in the
|
||||||
|
// constructor stats values for later inspection.
|
||||||
|
template <class T> void track_copy_created(T *inst) { ConstructorStats::get<T>().copy_created(inst); }
|
||||||
|
template <class T> void track_move_created(T *inst) { ConstructorStats::get<T>().move_created(inst); }
|
||||||
|
template <class T, typename... Values> void track_copy_assigned(T *, Values &&...values) {
|
||||||
|
auto &cst = ConstructorStats::get<T>();
|
||||||
|
cst.copy_assignments++;
|
||||||
|
cst.value(std::forward<Values>(values)...);
|
||||||
|
}
|
||||||
|
template <class T, typename... Values> void track_move_assigned(T *, Values &&...values) {
|
||||||
|
auto &cst = ConstructorStats::get<T>();
|
||||||
|
cst.move_assignments++;
|
||||||
|
cst.value(std::forward<Values>(values)...);
|
||||||
|
}
|
||||||
|
template <class T, typename... Values> void track_default_created(T *inst, Values &&...values) {
|
||||||
|
auto &cst = ConstructorStats::get<T>();
|
||||||
|
cst.default_created(inst);
|
||||||
|
cst.value(std::forward<Values>(values)...);
|
||||||
|
}
|
||||||
|
template <class T, typename... Values> void track_created(T *inst, Values &&...values) {
|
||||||
|
auto &cst = ConstructorStats::get<T>();
|
||||||
|
cst.created(inst);
|
||||||
|
cst.value(std::forward<Values>(values)...);
|
||||||
|
}
|
||||||
|
template <class T, typename... Values> void track_destroyed(T *inst) {
|
||||||
|
ConstructorStats::get<T>().destroyed(inst);
|
||||||
|
}
|
||||||
|
template <class T, typename... Values> void track_values(T *, Values &&...values) {
|
||||||
|
ConstructorStats::get<T>().value(std::forward<Values>(values)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Don't cast pointers to Python, print them as strings
|
||||||
|
inline const char *format_ptrs(const char *p) { return p; }
|
||||||
|
template <typename T>
|
||||||
|
py::str format_ptrs(T *p) { return "{:#x}"_s.format(reinterpret_cast<std::uintptr_t>(p)); }
|
||||||
|
template <typename T>
|
||||||
|
auto format_ptrs(T &&x) -> decltype(std::forward<T>(x)) { return std::forward<T>(x); }
|
||||||
|
|
||||||
|
template <class T, typename... Output>
|
||||||
|
void print_constr_details(T *inst, const std::string &action, Output &&...output) {
|
||||||
|
py::print("###", py::type_id<T>(), "@", format_ptrs(inst), action,
|
||||||
|
format_ptrs(std::forward<Output>(output))...);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verbose versions of the above:
|
||||||
|
template <class T, typename... Values> void print_copy_created(T *inst, Values &&...values) { // NB: this prints, but doesn't store, given values
|
||||||
|
print_constr_details(inst, "created via copy constructor", values...);
|
||||||
|
track_copy_created(inst);
|
||||||
|
}
|
||||||
|
template <class T, typename... Values> void print_move_created(T *inst, Values &&...values) { // NB: this prints, but doesn't store, given values
|
||||||
|
print_constr_details(inst, "created via move constructor", values...);
|
||||||
|
track_move_created(inst);
|
||||||
|
}
|
||||||
|
template <class T, typename... Values> void print_copy_assigned(T *inst, Values &&...values) {
|
||||||
|
print_constr_details(inst, "assigned via copy assignment", values...);
|
||||||
|
track_copy_assigned(inst, values...);
|
||||||
|
}
|
||||||
|
template <class T, typename... Values> void print_move_assigned(T *inst, Values &&...values) {
|
||||||
|
print_constr_details(inst, "assigned via move assignment", values...);
|
||||||
|
track_move_assigned(inst, values...);
|
||||||
|
}
|
||||||
|
template <class T, typename... Values> void print_default_created(T *inst, Values &&...values) {
|
||||||
|
print_constr_details(inst, "created via default constructor", values...);
|
||||||
|
track_default_created(inst, values...);
|
||||||
|
}
|
||||||
|
template <class T, typename... Values> void print_created(T *inst, Values &&...values) {
|
||||||
|
print_constr_details(inst, "created", values...);
|
||||||
|
track_created(inst, values...);
|
||||||
|
}
|
||||||
|
template <class T, typename... Values> void print_destroyed(T *inst, Values &&...values) { // Prints but doesn't store given values
|
||||||
|
print_constr_details(inst, "destroyed", values...);
|
||||||
|
track_destroyed(inst);
|
||||||
|
}
|
||||||
|
template <class T, typename... Values> void print_values(T *inst, Values &&...values) {
|
||||||
|
print_constr_details(inst, ":", values...);
|
||||||
|
track_values(inst, values...);
|
||||||
|
}
|
||||||
|
|
73
3rdparty/pybind11/tests/cross_module_gil_utils.cpp
vendored
Normal file
73
3rdparty/pybind11/tests/cross_module_gil_utils.cpp
vendored
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
/*
|
||||||
|
tests/cross_module_gil_utils.cpp -- tools for acquiring GIL from a different module
|
||||||
|
|
||||||
|
Copyright (c) 2019 Google LLC
|
||||||
|
|
||||||
|
All rights reserved. Use of this source code is governed by a
|
||||||
|
BSD-style license that can be found in the LICENSE file.
|
||||||
|
*/
|
||||||
|
#include <pybind11/pybind11.h>
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
// This file mimics a DSO that makes pybind11 calls but does not define a
|
||||||
|
// PYBIND11_MODULE. The purpose is to test that such a DSO can create a
|
||||||
|
// py::gil_scoped_acquire when the running thread is in a GIL-released state.
|
||||||
|
//
|
||||||
|
// Note that we define a Python module here for convenience, but in general
|
||||||
|
// this need not be the case. The typical scenario would be a DSO that implements
|
||||||
|
// shared logic used internally by multiple pybind11 modules.
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
namespace py = pybind11;
|
||||||
|
void gil_acquire() { py::gil_scoped_acquire gil; }
|
||||||
|
|
||||||
|
constexpr char kModuleName[] = "cross_module_gil_utils";
|
||||||
|
|
||||||
|
#if PY_MAJOR_VERSION >= 3
|
||||||
|
struct PyModuleDef moduledef = {
|
||||||
|
PyModuleDef_HEAD_INIT,
|
||||||
|
kModuleName,
|
||||||
|
NULL,
|
||||||
|
0,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
#else
|
||||||
|
PyMethodDef module_methods[] = {
|
||||||
|
{NULL, NULL, 0, NULL}
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
extern "C" PYBIND11_EXPORT
|
||||||
|
#if PY_MAJOR_VERSION >= 3
|
||||||
|
PyObject* PyInit_cross_module_gil_utils()
|
||||||
|
#else
|
||||||
|
void initcross_module_gil_utils()
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
|
||||||
|
PyObject* m =
|
||||||
|
#if PY_MAJOR_VERSION >= 3
|
||||||
|
PyModule_Create(&moduledef);
|
||||||
|
#else
|
||||||
|
Py_InitModule(kModuleName, module_methods);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (m != NULL) {
|
||||||
|
static_assert(
|
||||||
|
sizeof(&gil_acquire) == sizeof(void*),
|
||||||
|
"Function pointer must have the same size as void*");
|
||||||
|
PyModule_AddObject(m, "gil_acquire_funcaddr",
|
||||||
|
PyLong_FromVoidPtr(reinterpret_cast<void*>(&gil_acquire)));
|
||||||
|
}
|
||||||
|
|
||||||
|
#if PY_MAJOR_VERSION >= 3
|
||||||
|
return m;
|
||||||
|
#endif
|
||||||
|
}
|
64
3rdparty/pybind11/tests/local_bindings.h
vendored
Normal file
64
3rdparty/pybind11/tests/local_bindings.h
vendored
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "pybind11_tests.h"
|
||||||
|
|
||||||
|
/// Simple class used to test py::local:
|
||||||
|
template <int> class LocalBase {
|
||||||
|
public:
|
||||||
|
LocalBase(int i) : i(i) { }
|
||||||
|
int i = -1;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Registered with py::module_local in both main and secondary modules:
|
||||||
|
using LocalType = LocalBase<0>;
|
||||||
|
/// Registered without py::module_local in both modules:
|
||||||
|
using NonLocalType = LocalBase<1>;
|
||||||
|
/// A second non-local type (for stl_bind tests):
|
||||||
|
using NonLocal2 = LocalBase<2>;
|
||||||
|
/// Tests within-module, different-compilation-unit local definition conflict:
|
||||||
|
using LocalExternal = LocalBase<3>;
|
||||||
|
/// Mixed: registered local first, then global
|
||||||
|
using MixedLocalGlobal = LocalBase<4>;
|
||||||
|
/// Mixed: global first, then local
|
||||||
|
using MixedGlobalLocal = LocalBase<5>;
|
||||||
|
|
||||||
|
/// Registered with py::module_local only in the secondary module:
|
||||||
|
using ExternalType1 = LocalBase<6>;
|
||||||
|
using ExternalType2 = LocalBase<7>;
|
||||||
|
|
||||||
|
using LocalVec = std::vector<LocalType>;
|
||||||
|
using LocalVec2 = std::vector<NonLocal2>;
|
||||||
|
using LocalMap = std::unordered_map<std::string, LocalType>;
|
||||||
|
using NonLocalVec = std::vector<NonLocalType>;
|
||||||
|
using NonLocalVec2 = std::vector<NonLocal2>;
|
||||||
|
using NonLocalMap = std::unordered_map<std::string, NonLocalType>;
|
||||||
|
using NonLocalMap2 = std::unordered_map<std::string, uint8_t>;
|
||||||
|
|
||||||
|
PYBIND11_MAKE_OPAQUE(LocalVec);
|
||||||
|
PYBIND11_MAKE_OPAQUE(LocalVec2);
|
||||||
|
PYBIND11_MAKE_OPAQUE(LocalMap);
|
||||||
|
PYBIND11_MAKE_OPAQUE(NonLocalVec);
|
||||||
|
//PYBIND11_MAKE_OPAQUE(NonLocalVec2); // same type as LocalVec2
|
||||||
|
PYBIND11_MAKE_OPAQUE(NonLocalMap);
|
||||||
|
PYBIND11_MAKE_OPAQUE(NonLocalMap2);
|
||||||
|
|
||||||
|
|
||||||
|
// Simple bindings (used with the above):
|
||||||
|
template <typename T, int Adjust = 0, typename... Args>
|
||||||
|
py::class_<T> bind_local(Args && ...args) {
|
||||||
|
return py::class_<T>(std::forward<Args>(args)...)
|
||||||
|
.def(py::init<int>())
|
||||||
|
.def("get", [](T &i) { return i.i + Adjust; });
|
||||||
|
};
|
||||||
|
|
||||||
|
// Simulate a foreign library base class (to match the example in the docs):
|
||||||
|
namespace pets {
|
||||||
|
class Pet {
|
||||||
|
public:
|
||||||
|
Pet(std::string name) : name_(name) {}
|
||||||
|
std::string name_;
|
||||||
|
const std::string &name() { return name_; }
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
struct MixGL { int i; MixGL(int i) : i{i} {} };
|
||||||
|
struct MixGL2 { int i; MixGL2(int i) : i{i} {} };
|
175
3rdparty/pybind11/tests/object.h
vendored
Normal file
175
3rdparty/pybind11/tests/object.h
vendored
Normal file
@ -0,0 +1,175 @@
|
|||||||
|
#if !defined(__OBJECT_H)
|
||||||
|
#define __OBJECT_H
|
||||||
|
|
||||||
|
#include <atomic>
|
||||||
|
#include "constructor_stats.h"
|
||||||
|
|
||||||
|
/// Reference counted object base class
|
||||||
|
class Object {
|
||||||
|
public:
|
||||||
|
/// Default constructor
|
||||||
|
Object() { print_default_created(this); }
|
||||||
|
|
||||||
|
/// Copy constructor
|
||||||
|
Object(const Object &) : m_refCount(0) { print_copy_created(this); }
|
||||||
|
|
||||||
|
/// Return the current reference count
|
||||||
|
int getRefCount() const { return m_refCount; };
|
||||||
|
|
||||||
|
/// Increase the object's reference count by one
|
||||||
|
void incRef() const { ++m_refCount; }
|
||||||
|
|
||||||
|
/** \brief Decrease the reference count of
|
||||||
|
* the object and possibly deallocate it.
|
||||||
|
*
|
||||||
|
* The object will automatically be deallocated once
|
||||||
|
* the reference count reaches zero.
|
||||||
|
*/
|
||||||
|
void decRef(bool dealloc = true) const {
|
||||||
|
--m_refCount;
|
||||||
|
if (m_refCount == 0 && dealloc)
|
||||||
|
delete this;
|
||||||
|
else if (m_refCount < 0)
|
||||||
|
throw std::runtime_error("Internal error: reference count < 0!");
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual std::string toString() const = 0;
|
||||||
|
protected:
|
||||||
|
/** \brief Virtual protected deconstructor.
|
||||||
|
* (Will only be called by \ref ref)
|
||||||
|
*/
|
||||||
|
virtual ~Object() { print_destroyed(this); }
|
||||||
|
private:
|
||||||
|
mutable std::atomic<int> m_refCount { 0 };
|
||||||
|
};
|
||||||
|
|
||||||
|
// Tag class used to track constructions of ref objects. When we track constructors, below, we
|
||||||
|
// track and print out the actual class (e.g. ref<MyObject>), and *also* add a fake tracker for
|
||||||
|
// ref_tag. This lets us check that the total number of ref<Anything> constructors/destructors is
|
||||||
|
// correct without having to check each individual ref<Whatever> type individually.
|
||||||
|
class ref_tag {};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Reference counting helper
|
||||||
|
*
|
||||||
|
* The \a ref refeference template is a simple wrapper to store a
|
||||||
|
* pointer to an object. It takes care of increasing and decreasing
|
||||||
|
* the reference count of the object. When the last reference goes
|
||||||
|
* out of scope, the associated object will be deallocated.
|
||||||
|
*
|
||||||
|
* \ingroup libcore
|
||||||
|
*/
|
||||||
|
template <typename T> class ref {
|
||||||
|
public:
|
||||||
|
/// Create a nullptr reference
|
||||||
|
ref() : m_ptr(nullptr) { print_default_created(this); track_default_created((ref_tag*) this); }
|
||||||
|
|
||||||
|
/// Construct a reference from a pointer
|
||||||
|
ref(T *ptr) : m_ptr(ptr) {
|
||||||
|
if (m_ptr) ((Object *) m_ptr)->incRef();
|
||||||
|
|
||||||
|
print_created(this, "from pointer", m_ptr); track_created((ref_tag*) this, "from pointer");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Copy constructor
|
||||||
|
ref(const ref &r) : m_ptr(r.m_ptr) {
|
||||||
|
if (m_ptr)
|
||||||
|
((Object *) m_ptr)->incRef();
|
||||||
|
|
||||||
|
print_copy_created(this, "with pointer", m_ptr); track_copy_created((ref_tag*) this);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Move constructor
|
||||||
|
ref(ref &&r) : m_ptr(r.m_ptr) {
|
||||||
|
r.m_ptr = nullptr;
|
||||||
|
|
||||||
|
print_move_created(this, "with pointer", m_ptr); track_move_created((ref_tag*) this);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Destroy this reference
|
||||||
|
~ref() {
|
||||||
|
if (m_ptr)
|
||||||
|
((Object *) m_ptr)->decRef();
|
||||||
|
|
||||||
|
print_destroyed(this); track_destroyed((ref_tag*) this);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Move another reference into the current one
|
||||||
|
ref& operator=(ref&& r) {
|
||||||
|
print_move_assigned(this, "pointer", r.m_ptr); track_move_assigned((ref_tag*) this);
|
||||||
|
|
||||||
|
if (*this == r)
|
||||||
|
return *this;
|
||||||
|
if (m_ptr)
|
||||||
|
((Object *) m_ptr)->decRef();
|
||||||
|
m_ptr = r.m_ptr;
|
||||||
|
r.m_ptr = nullptr;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Overwrite this reference with another reference
|
||||||
|
ref& operator=(const ref& r) {
|
||||||
|
print_copy_assigned(this, "pointer", r.m_ptr); track_copy_assigned((ref_tag*) this);
|
||||||
|
|
||||||
|
if (m_ptr == r.m_ptr)
|
||||||
|
return *this;
|
||||||
|
if (m_ptr)
|
||||||
|
((Object *) m_ptr)->decRef();
|
||||||
|
m_ptr = r.m_ptr;
|
||||||
|
if (m_ptr)
|
||||||
|
((Object *) m_ptr)->incRef();
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Overwrite this reference with a pointer to another object
|
||||||
|
ref& operator=(T *ptr) {
|
||||||
|
print_values(this, "assigned pointer"); track_values((ref_tag*) this, "assigned pointer");
|
||||||
|
|
||||||
|
if (m_ptr == ptr)
|
||||||
|
return *this;
|
||||||
|
if (m_ptr)
|
||||||
|
((Object *) m_ptr)->decRef();
|
||||||
|
m_ptr = ptr;
|
||||||
|
if (m_ptr)
|
||||||
|
((Object *) m_ptr)->incRef();
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Compare this reference with another reference
|
||||||
|
bool operator==(const ref &r) const { return m_ptr == r.m_ptr; }
|
||||||
|
|
||||||
|
/// Compare this reference with another reference
|
||||||
|
bool operator!=(const ref &r) const { return m_ptr != r.m_ptr; }
|
||||||
|
|
||||||
|
/// Compare this reference with a pointer
|
||||||
|
bool operator==(const T* ptr) const { return m_ptr == ptr; }
|
||||||
|
|
||||||
|
/// Compare this reference with a pointer
|
||||||
|
bool operator!=(const T* ptr) const { return m_ptr != ptr; }
|
||||||
|
|
||||||
|
/// Access the object referenced by this reference
|
||||||
|
T* operator->() { return m_ptr; }
|
||||||
|
|
||||||
|
/// Access the object referenced by this reference
|
||||||
|
const T* operator->() const { return m_ptr; }
|
||||||
|
|
||||||
|
/// Return a C++ reference to the referenced object
|
||||||
|
T& operator*() { return *m_ptr; }
|
||||||
|
|
||||||
|
/// Return a const C++ reference to the referenced object
|
||||||
|
const T& operator*() const { return *m_ptr; }
|
||||||
|
|
||||||
|
/// Return a pointer to the referenced object
|
||||||
|
operator T* () { return m_ptr; }
|
||||||
|
|
||||||
|
/// Return a const pointer to the referenced object
|
||||||
|
T* get_ptr() { return m_ptr; }
|
||||||
|
|
||||||
|
/// Return a pointer to the referenced object
|
||||||
|
const T* get_ptr() const { return m_ptr; }
|
||||||
|
private:
|
||||||
|
T *m_ptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* __OBJECT_H */
|
123
3rdparty/pybind11/tests/pybind11_cross_module_tests.cpp
vendored
Normal file
123
3rdparty/pybind11/tests/pybind11_cross_module_tests.cpp
vendored
Normal file
@ -0,0 +1,123 @@
|
|||||||
|
/*
|
||||||
|
tests/pybind11_cross_module_tests.cpp -- contains tests that require multiple modules
|
||||||
|
|
||||||
|
Copyright (c) 2017 Jason Rhinelander <jason@imaginary.ca>
|
||||||
|
|
||||||
|
All rights reserved. Use of this source code is governed by a
|
||||||
|
BSD-style license that can be found in the LICENSE file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "pybind11_tests.h"
|
||||||
|
#include "local_bindings.h"
|
||||||
|
#include <pybind11/stl_bind.h>
|
||||||
|
#include <numeric>
|
||||||
|
|
||||||
|
PYBIND11_MODULE(pybind11_cross_module_tests, m) {
|
||||||
|
m.doc() = "pybind11 cross-module test module";
|
||||||
|
|
||||||
|
// test_local_bindings.py tests:
|
||||||
|
//
|
||||||
|
// Definitions here are tested by importing both this module and the
|
||||||
|
// relevant pybind11_tests submodule from a test_whatever.py
|
||||||
|
|
||||||
|
// test_load_external
|
||||||
|
bind_local<ExternalType1>(m, "ExternalType1", py::module_local());
|
||||||
|
bind_local<ExternalType2>(m, "ExternalType2", py::module_local());
|
||||||
|
|
||||||
|
// test_exceptions.py
|
||||||
|
m.def("raise_runtime_error", []() { PyErr_SetString(PyExc_RuntimeError, "My runtime error"); throw py::error_already_set(); });
|
||||||
|
m.def("raise_value_error", []() { PyErr_SetString(PyExc_ValueError, "My value error"); throw py::error_already_set(); });
|
||||||
|
m.def("throw_pybind_value_error", []() { throw py::value_error("pybind11 value error"); });
|
||||||
|
m.def("throw_pybind_type_error", []() { throw py::type_error("pybind11 type error"); });
|
||||||
|
m.def("throw_stop_iteration", []() { throw py::stop_iteration(); });
|
||||||
|
|
||||||
|
// test_local_bindings.py
|
||||||
|
// Local to both:
|
||||||
|
bind_local<LocalType, 1>(m, "LocalType", py::module_local())
|
||||||
|
.def("get2", [](LocalType &t) { return t.i + 2; })
|
||||||
|
;
|
||||||
|
|
||||||
|
// Can only be called with our python type:
|
||||||
|
m.def("local_value", [](LocalType &l) { return l.i; });
|
||||||
|
|
||||||
|
// test_nonlocal_failure
|
||||||
|
// This registration will fail (global registration when LocalFail is already registered
|
||||||
|
// globally in the main test module):
|
||||||
|
m.def("register_nonlocal", [m]() {
|
||||||
|
bind_local<NonLocalType, 0>(m, "NonLocalType");
|
||||||
|
});
|
||||||
|
|
||||||
|
// test_stl_bind_local
|
||||||
|
// stl_bind.h binders defaults to py::module_local if the types are local or converting:
|
||||||
|
py::bind_vector<LocalVec>(m, "LocalVec");
|
||||||
|
py::bind_map<LocalMap>(m, "LocalMap");
|
||||||
|
|
||||||
|
// test_stl_bind_global
|
||||||
|
// and global if the type (or one of the types, for the map) is global (so these will fail,
|
||||||
|
// assuming pybind11_tests is already loaded):
|
||||||
|
m.def("register_nonlocal_vec", [m]() {
|
||||||
|
py::bind_vector<NonLocalVec>(m, "NonLocalVec");
|
||||||
|
});
|
||||||
|
m.def("register_nonlocal_map", [m]() {
|
||||||
|
py::bind_map<NonLocalMap>(m, "NonLocalMap");
|
||||||
|
});
|
||||||
|
// The default can, however, be overridden to global using `py::module_local()` or
|
||||||
|
// `py::module_local(false)`.
|
||||||
|
// Explicitly made local:
|
||||||
|
py::bind_vector<NonLocalVec2>(m, "NonLocalVec2", py::module_local());
|
||||||
|
// Explicitly made global (and so will fail to bind):
|
||||||
|
m.def("register_nonlocal_map2", [m]() {
|
||||||
|
py::bind_map<NonLocalMap2>(m, "NonLocalMap2", py::module_local(false));
|
||||||
|
});
|
||||||
|
|
||||||
|
// test_mixed_local_global
|
||||||
|
// We try this both with the global type registered first and vice versa (the order shouldn't
|
||||||
|
// matter).
|
||||||
|
m.def("register_mixed_global_local", [m]() {
|
||||||
|
bind_local<MixedGlobalLocal, 200>(m, "MixedGlobalLocal", py::module_local());
|
||||||
|
});
|
||||||
|
m.def("register_mixed_local_global", [m]() {
|
||||||
|
bind_local<MixedLocalGlobal, 2000>(m, "MixedLocalGlobal", py::module_local(false));
|
||||||
|
});
|
||||||
|
m.def("get_mixed_gl", [](int i) { return MixedGlobalLocal(i); });
|
||||||
|
m.def("get_mixed_lg", [](int i) { return MixedLocalGlobal(i); });
|
||||||
|
|
||||||
|
// test_internal_locals_differ
|
||||||
|
m.def("local_cpp_types_addr", []() { return (uintptr_t) &py::detail::registered_local_types_cpp(); });
|
||||||
|
|
||||||
|
// test_stl_caster_vs_stl_bind
|
||||||
|
py::bind_vector<std::vector<int>>(m, "VectorInt");
|
||||||
|
|
||||||
|
m.def("load_vector_via_binding", [](std::vector<int> &v) {
|
||||||
|
return std::accumulate(v.begin(), v.end(), 0);
|
||||||
|
});
|
||||||
|
|
||||||
|
// test_cross_module_calls
|
||||||
|
m.def("return_self", [](LocalVec *v) { return v; });
|
||||||
|
m.def("return_copy", [](const LocalVec &v) { return LocalVec(v); });
|
||||||
|
|
||||||
|
class Dog : public pets::Pet { public: Dog(std::string name) : Pet(name) {}; };
|
||||||
|
py::class_<pets::Pet>(m, "Pet", py::module_local())
|
||||||
|
.def("name", &pets::Pet::name);
|
||||||
|
// Binding for local extending class:
|
||||||
|
py::class_<Dog, pets::Pet>(m, "Dog")
|
||||||
|
.def(py::init<std::string>());
|
||||||
|
m.def("pet_name", [](pets::Pet &p) { return p.name(); });
|
||||||
|
|
||||||
|
py::class_<MixGL>(m, "MixGL", py::module_local()).def(py::init<int>());
|
||||||
|
m.def("get_gl_value", [](MixGL &o) { return o.i + 100; });
|
||||||
|
|
||||||
|
py::class_<MixGL2>(m, "MixGL2", py::module_local()).def(py::init<int>());
|
||||||
|
|
||||||
|
// test_vector_bool
|
||||||
|
// We can't test both stl.h and stl_bind.h conversions of `std::vector<bool>` within
|
||||||
|
// the same module (it would be an ODR violation). Therefore `bind_vector` of `bool`
|
||||||
|
// is defined here and tested in `test_stl_binders.py`.
|
||||||
|
py::bind_vector<std::vector<bool>>(m, "VectorBool");
|
||||||
|
|
||||||
|
// test_missing_header_message
|
||||||
|
// The main module already includes stl.h, but we need to test the error message
|
||||||
|
// which appears when this header is missing.
|
||||||
|
m.def("missing_header_arg", [](std::vector<float>) { });
|
||||||
|
m.def("missing_header_return", []() { return std::vector<float>(); });
|
||||||
|
}
|
93
3rdparty/pybind11/tests/pybind11_tests.cpp
vendored
Normal file
93
3rdparty/pybind11/tests/pybind11_tests.cpp
vendored
Normal file
@ -0,0 +1,93 @@
|
|||||||
|
/*
|
||||||
|
tests/pybind11_tests.cpp -- pybind example plugin
|
||||||
|
|
||||||
|
Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch>
|
||||||
|
|
||||||
|
All rights reserved. Use of this source code is governed by a
|
||||||
|
BSD-style license that can be found in the LICENSE file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "pybind11_tests.h"
|
||||||
|
#include "constructor_stats.h"
|
||||||
|
|
||||||
|
#include <functional>
|
||||||
|
#include <list>
|
||||||
|
|
||||||
|
/*
|
||||||
|
For testing purposes, we define a static global variable here in a function that each individual
|
||||||
|
test .cpp calls with its initialization lambda. It's convenient here because we can just not
|
||||||
|
compile some test files to disable/ignore some of the test code.
|
||||||
|
|
||||||
|
It is NOT recommended as a way to use pybind11 in practice, however: the initialization order will
|
||||||
|
be essentially random, which is okay for our test scripts (there are no dependencies between the
|
||||||
|
individual pybind11 test .cpp files), but most likely not what you want when using pybind11
|
||||||
|
productively.
|
||||||
|
|
||||||
|
Instead, see the "How can I reduce the build time?" question in the "Frequently asked questions"
|
||||||
|
section of the documentation for good practice on splitting binding code over multiple files.
|
||||||
|
*/
|
||||||
|
std::list<std::function<void(py::module &)>> &initializers() {
|
||||||
|
static std::list<std::function<void(py::module &)>> inits;
|
||||||
|
return inits;
|
||||||
|
}
|
||||||
|
|
||||||
|
test_initializer::test_initializer(Initializer init) {
|
||||||
|
initializers().push_back(init);
|
||||||
|
}
|
||||||
|
|
||||||
|
test_initializer::test_initializer(const char *submodule_name, Initializer init) {
|
||||||
|
initializers().push_back([=](py::module &parent) {
|
||||||
|
auto m = parent.def_submodule(submodule_name);
|
||||||
|
init(m);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void bind_ConstructorStats(py::module &m) {
|
||||||
|
py::class_<ConstructorStats>(m, "ConstructorStats")
|
||||||
|
.def("alive", &ConstructorStats::alive)
|
||||||
|
.def("values", &ConstructorStats::values)
|
||||||
|
.def_readwrite("default_constructions", &ConstructorStats::default_constructions)
|
||||||
|
.def_readwrite("copy_assignments", &ConstructorStats::copy_assignments)
|
||||||
|
.def_readwrite("move_assignments", &ConstructorStats::move_assignments)
|
||||||
|
.def_readwrite("copy_constructions", &ConstructorStats::copy_constructions)
|
||||||
|
.def_readwrite("move_constructions", &ConstructorStats::move_constructions)
|
||||||
|
.def_static("get", (ConstructorStats &(*)(py::object)) &ConstructorStats::get, py::return_value_policy::reference_internal)
|
||||||
|
|
||||||
|
// Not exactly ConstructorStats, but related: expose the internal pybind number of registered instances
|
||||||
|
// to allow instance cleanup checks (invokes a GC first)
|
||||||
|
.def_static("detail_reg_inst", []() {
|
||||||
|
ConstructorStats::gc();
|
||||||
|
return py::detail::get_internals().registered_instances.size();
|
||||||
|
})
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
PYBIND11_MODULE(pybind11_tests, m) {
|
||||||
|
m.doc() = "pybind11 test module";
|
||||||
|
|
||||||
|
bind_ConstructorStats(m);
|
||||||
|
|
||||||
|
#if !defined(NDEBUG)
|
||||||
|
m.attr("debug_enabled") = true;
|
||||||
|
#else
|
||||||
|
m.attr("debug_enabled") = false;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
py::class_<UserType>(m, "UserType", "A `py::class_` type for testing")
|
||||||
|
.def(py::init<>())
|
||||||
|
.def(py::init<int>())
|
||||||
|
.def("get_value", &UserType::value, "Get value using a method")
|
||||||
|
.def("set_value", &UserType::set, "Set value using a method")
|
||||||
|
.def_property("value", &UserType::value, &UserType::set, "Get/set value using a property")
|
||||||
|
.def("__repr__", [](const UserType& u) { return "UserType({})"_s.format(u.value()); });
|
||||||
|
|
||||||
|
py::class_<IncType, UserType>(m, "IncType")
|
||||||
|
.def(py::init<>())
|
||||||
|
.def(py::init<int>())
|
||||||
|
.def("__repr__", [](const IncType& u) { return "IncType({})"_s.format(u.value()); });
|
||||||
|
|
||||||
|
for (const auto &initializer : initializers())
|
||||||
|
initializer(m);
|
||||||
|
|
||||||
|
if (!py::hasattr(m, "have_eigen")) m.attr("have_eigen") = false;
|
||||||
|
}
|
65
3rdparty/pybind11/tests/pybind11_tests.h
vendored
Normal file
65
3rdparty/pybind11/tests/pybind11_tests.h
vendored
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <pybind11/pybind11.h>
|
||||||
|
|
||||||
|
#if defined(_MSC_VER) && _MSC_VER < 1910
|
||||||
|
// We get some really long type names here which causes MSVC 2015 to emit warnings
|
||||||
|
# pragma warning(disable: 4503) // warning C4503: decorated name length exceeded, name was truncated
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace py = pybind11;
|
||||||
|
using namespace pybind11::literals;
|
||||||
|
|
||||||
|
class test_initializer {
|
||||||
|
using Initializer = void (*)(py::module &);
|
||||||
|
|
||||||
|
public:
|
||||||
|
test_initializer(Initializer init);
|
||||||
|
test_initializer(const char *submodule_name, Initializer init);
|
||||||
|
};
|
||||||
|
|
||||||
|
#define TEST_SUBMODULE(name, variable) \
|
||||||
|
void test_submodule_##name(py::module &); \
|
||||||
|
test_initializer name(#name, test_submodule_##name); \
|
||||||
|
void test_submodule_##name(py::module &variable)
|
||||||
|
|
||||||
|
|
||||||
|
/// Dummy type which is not exported anywhere -- something to trigger a conversion error
|
||||||
|
struct UnregisteredType { };
|
||||||
|
|
||||||
|
/// A user-defined type which is exported and can be used by any test
|
||||||
|
class UserType {
|
||||||
|
public:
|
||||||
|
UserType() = default;
|
||||||
|
UserType(int i) : i(i) { }
|
||||||
|
|
||||||
|
int value() const { return i; }
|
||||||
|
void set(int set) { i = set; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
int i = -1;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Like UserType, but increments `value` on copy for quick reference vs. copy tests
|
||||||
|
class IncType : public UserType {
|
||||||
|
public:
|
||||||
|
using UserType::UserType;
|
||||||
|
IncType() = default;
|
||||||
|
IncType(const IncType &other) : IncType(other.value() + 1) { }
|
||||||
|
IncType(IncType &&) = delete;
|
||||||
|
IncType &operator=(const IncType &) = delete;
|
||||||
|
IncType &operator=(IncType &&) = delete;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Custom cast-only type that casts to a string "rvalue" or "lvalue" depending on the cast context.
|
||||||
|
/// Used to test recursive casters (e.g. std::tuple, stl containers).
|
||||||
|
struct RValueCaster {};
|
||||||
|
NAMESPACE_BEGIN(pybind11)
|
||||||
|
NAMESPACE_BEGIN(detail)
|
||||||
|
template<> class type_caster<RValueCaster> {
|
||||||
|
public:
|
||||||
|
PYBIND11_TYPE_CASTER(RValueCaster, _("RValueCaster"));
|
||||||
|
static handle cast(RValueCaster &&, return_value_policy, handle) { return py::str("rvalue").release(); }
|
||||||
|
static handle cast(const RValueCaster &, return_value_policy, handle) { return py::str("lvalue").release(); }
|
||||||
|
};
|
||||||
|
NAMESPACE_END(detail)
|
||||||
|
NAMESPACE_END(pybind11)
|
16
3rdparty/pybind11/tests/pytest.ini
vendored
Normal file
16
3rdparty/pybind11/tests/pytest.ini
vendored
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
[pytest]
|
||||||
|
minversion = 3.0
|
||||||
|
norecursedirs = test_cmake_build test_embed
|
||||||
|
addopts =
|
||||||
|
# show summary of skipped tests
|
||||||
|
-rs
|
||||||
|
# capture only Python print and C++ py::print, but not C output (low-level Python errors)
|
||||||
|
--capture=sys
|
||||||
|
filterwarnings =
|
||||||
|
# make warnings into errors but ignore certain third-party extension issues
|
||||||
|
error
|
||||||
|
# importing scipy submodules on some version of Python
|
||||||
|
ignore::ImportWarning
|
||||||
|
# bogus numpy ABI warning (see numpy/#432)
|
||||||
|
ignore:.*numpy.dtype size changed.*:RuntimeWarning
|
||||||
|
ignore:.*numpy.ufunc size changed.*:RuntimeWarning
|
26
3rdparty/pybind11/tests/test_async.cpp
vendored
Normal file
26
3rdparty/pybind11/tests/test_async.cpp
vendored
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
/*
|
||||||
|
tests/test_async.cpp -- __await__ support
|
||||||
|
|
||||||
|
Copyright (c) 2019 Google Inc.
|
||||||
|
|
||||||
|
All rights reserved. Use of this source code is governed by a
|
||||||
|
BSD-style license that can be found in the LICENSE file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "pybind11_tests.h"
|
||||||
|
|
||||||
|
TEST_SUBMODULE(async_module, m) {
|
||||||
|
struct DoesNotSupportAsync {};
|
||||||
|
py::class_<DoesNotSupportAsync>(m, "DoesNotSupportAsync")
|
||||||
|
.def(py::init<>());
|
||||||
|
struct SupportsAsync {};
|
||||||
|
py::class_<SupportsAsync>(m, "SupportsAsync")
|
||||||
|
.def(py::init<>())
|
||||||
|
.def("__await__", [](const SupportsAsync& self) -> py::object {
|
||||||
|
static_cast<void>(self);
|
||||||
|
py::object loop = py::module::import("asyncio.events").attr("get_event_loop")();
|
||||||
|
py::object f = loop.attr("create_future")();
|
||||||
|
f.attr("set_result")(5);
|
||||||
|
return f.attr("__await__")();
|
||||||
|
});
|
||||||
|
}
|
23
3rdparty/pybind11/tests/test_async.py
vendored
Normal file
23
3rdparty/pybind11/tests/test_async.py
vendored
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
import asyncio
|
||||||
|
import pytest
|
||||||
|
from pybind11_tests import async_module as m
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def event_loop():
|
||||||
|
loop = asyncio.new_event_loop()
|
||||||
|
yield loop
|
||||||
|
loop.close()
|
||||||
|
|
||||||
|
|
||||||
|
async def get_await_result(x):
|
||||||
|
return await x
|
||||||
|
|
||||||
|
|
||||||
|
def test_await(event_loop):
|
||||||
|
assert 5 == event_loop.run_until_complete(get_await_result(m.SupportsAsync()))
|
||||||
|
|
||||||
|
|
||||||
|
def test_await_missing(event_loop):
|
||||||
|
with pytest.raises(TypeError):
|
||||||
|
event_loop.run_until_complete(get_await_result(m.DoesNotSupportAsync()))
|
195
3rdparty/pybind11/tests/test_buffers.cpp
vendored
Normal file
195
3rdparty/pybind11/tests/test_buffers.cpp
vendored
Normal file
@ -0,0 +1,195 @@
|
|||||||
|
/*
|
||||||
|
tests/test_buffers.cpp -- supporting Pythons' buffer protocol
|
||||||
|
|
||||||
|
Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch>
|
||||||
|
|
||||||
|
All rights reserved. Use of this source code is governed by a
|
||||||
|
BSD-style license that can be found in the LICENSE file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "pybind11_tests.h"
|
||||||
|
#include "constructor_stats.h"
|
||||||
|
|
||||||
|
TEST_SUBMODULE(buffers, m) {
|
||||||
|
// test_from_python / test_to_python:
|
||||||
|
class Matrix {
|
||||||
|
public:
|
||||||
|
Matrix(ssize_t rows, ssize_t cols) : m_rows(rows), m_cols(cols) {
|
||||||
|
print_created(this, std::to_string(m_rows) + "x" + std::to_string(m_cols) + " matrix");
|
||||||
|
m_data = new float[(size_t) (rows*cols)];
|
||||||
|
memset(m_data, 0, sizeof(float) * (size_t) (rows * cols));
|
||||||
|
}
|
||||||
|
|
||||||
|
Matrix(const Matrix &s) : m_rows(s.m_rows), m_cols(s.m_cols) {
|
||||||
|
print_copy_created(this, std::to_string(m_rows) + "x" + std::to_string(m_cols) + " matrix");
|
||||||
|
m_data = new float[(size_t) (m_rows * m_cols)];
|
||||||
|
memcpy(m_data, s.m_data, sizeof(float) * (size_t) (m_rows * m_cols));
|
||||||
|
}
|
||||||
|
|
||||||
|
Matrix(Matrix &&s) : m_rows(s.m_rows), m_cols(s.m_cols), m_data(s.m_data) {
|
||||||
|
print_move_created(this);
|
||||||
|
s.m_rows = 0;
|
||||||
|
s.m_cols = 0;
|
||||||
|
s.m_data = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
~Matrix() {
|
||||||
|
print_destroyed(this, std::to_string(m_rows) + "x" + std::to_string(m_cols) + " matrix");
|
||||||
|
delete[] m_data;
|
||||||
|
}
|
||||||
|
|
||||||
|
Matrix &operator=(const Matrix &s) {
|
||||||
|
print_copy_assigned(this, std::to_string(m_rows) + "x" + std::to_string(m_cols) + " matrix");
|
||||||
|
delete[] m_data;
|
||||||
|
m_rows = s.m_rows;
|
||||||
|
m_cols = s.m_cols;
|
||||||
|
m_data = new float[(size_t) (m_rows * m_cols)];
|
||||||
|
memcpy(m_data, s.m_data, sizeof(float) * (size_t) (m_rows * m_cols));
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
Matrix &operator=(Matrix &&s) {
|
||||||
|
print_move_assigned(this, std::to_string(m_rows) + "x" + std::to_string(m_cols) + " matrix");
|
||||||
|
if (&s != this) {
|
||||||
|
delete[] m_data;
|
||||||
|
m_rows = s.m_rows; m_cols = s.m_cols; m_data = s.m_data;
|
||||||
|
s.m_rows = 0; s.m_cols = 0; s.m_data = nullptr;
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
float operator()(ssize_t i, ssize_t j) const {
|
||||||
|
return m_data[(size_t) (i*m_cols + j)];
|
||||||
|
}
|
||||||
|
|
||||||
|
float &operator()(ssize_t i, ssize_t j) {
|
||||||
|
return m_data[(size_t) (i*m_cols + j)];
|
||||||
|
}
|
||||||
|
|
||||||
|
float *data() { return m_data; }
|
||||||
|
|
||||||
|
ssize_t rows() const { return m_rows; }
|
||||||
|
ssize_t cols() const { return m_cols; }
|
||||||
|
private:
|
||||||
|
ssize_t m_rows;
|
||||||
|
ssize_t m_cols;
|
||||||
|
float *m_data;
|
||||||
|
};
|
||||||
|
py::class_<Matrix>(m, "Matrix", py::buffer_protocol())
|
||||||
|
.def(py::init<ssize_t, ssize_t>())
|
||||||
|
/// Construct from a buffer
|
||||||
|
.def(py::init([](py::buffer const b) {
|
||||||
|
py::buffer_info info = b.request();
|
||||||
|
if (info.format != py::format_descriptor<float>::format() || info.ndim != 2)
|
||||||
|
throw std::runtime_error("Incompatible buffer format!");
|
||||||
|
|
||||||
|
auto v = new Matrix(info.shape[0], info.shape[1]);
|
||||||
|
memcpy(v->data(), info.ptr, sizeof(float) * (size_t) (v->rows() * v->cols()));
|
||||||
|
return v;
|
||||||
|
}))
|
||||||
|
|
||||||
|
.def("rows", &Matrix::rows)
|
||||||
|
.def("cols", &Matrix::cols)
|
||||||
|
|
||||||
|
/// Bare bones interface
|
||||||
|
.def("__getitem__", [](const Matrix &m, std::pair<ssize_t, ssize_t> i) {
|
||||||
|
if (i.first >= m.rows() || i.second >= m.cols())
|
||||||
|
throw py::index_error();
|
||||||
|
return m(i.first, i.second);
|
||||||
|
})
|
||||||
|
.def("__setitem__", [](Matrix &m, std::pair<ssize_t, ssize_t> i, float v) {
|
||||||
|
if (i.first >= m.rows() || i.second >= m.cols())
|
||||||
|
throw py::index_error();
|
||||||
|
m(i.first, i.second) = v;
|
||||||
|
})
|
||||||
|
/// Provide buffer access
|
||||||
|
.def_buffer([](Matrix &m) -> py::buffer_info {
|
||||||
|
return py::buffer_info(
|
||||||
|
m.data(), /* Pointer to buffer */
|
||||||
|
{ m.rows(), m.cols() }, /* Buffer dimensions */
|
||||||
|
{ sizeof(float) * size_t(m.cols()), /* Strides (in bytes) for each index */
|
||||||
|
sizeof(float) }
|
||||||
|
);
|
||||||
|
})
|
||||||
|
;
|
||||||
|
|
||||||
|
|
||||||
|
// test_inherited_protocol
|
||||||
|
class SquareMatrix : public Matrix {
|
||||||
|
public:
|
||||||
|
SquareMatrix(ssize_t n) : Matrix(n, n) { }
|
||||||
|
};
|
||||||
|
// Derived classes inherit the buffer protocol and the buffer access function
|
||||||
|
py::class_<SquareMatrix, Matrix>(m, "SquareMatrix")
|
||||||
|
.def(py::init<ssize_t>());
|
||||||
|
|
||||||
|
|
||||||
|
// test_pointer_to_member_fn
|
||||||
|
// Tests that passing a pointer to member to the base class works in
|
||||||
|
// the derived class.
|
||||||
|
struct Buffer {
|
||||||
|
int32_t value = 0;
|
||||||
|
|
||||||
|
py::buffer_info get_buffer_info() {
|
||||||
|
return py::buffer_info(&value, sizeof(value),
|
||||||
|
py::format_descriptor<int32_t>::format(), 1);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
py::class_<Buffer>(m, "Buffer", py::buffer_protocol())
|
||||||
|
.def(py::init<>())
|
||||||
|
.def_readwrite("value", &Buffer::value)
|
||||||
|
.def_buffer(&Buffer::get_buffer_info);
|
||||||
|
|
||||||
|
|
||||||
|
class ConstBuffer {
|
||||||
|
std::unique_ptr<int32_t> value;
|
||||||
|
|
||||||
|
public:
|
||||||
|
int32_t get_value() const { return *value; }
|
||||||
|
void set_value(int32_t v) { *value = v; }
|
||||||
|
|
||||||
|
py::buffer_info get_buffer_info() const {
|
||||||
|
return py::buffer_info(value.get(), sizeof(*value),
|
||||||
|
py::format_descriptor<int32_t>::format(), 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
ConstBuffer() : value(new int32_t{0}) { };
|
||||||
|
};
|
||||||
|
py::class_<ConstBuffer>(m, "ConstBuffer", py::buffer_protocol())
|
||||||
|
.def(py::init<>())
|
||||||
|
.def_property("value", &ConstBuffer::get_value, &ConstBuffer::set_value)
|
||||||
|
.def_buffer(&ConstBuffer::get_buffer_info);
|
||||||
|
|
||||||
|
struct DerivedBuffer : public Buffer { };
|
||||||
|
py::class_<DerivedBuffer>(m, "DerivedBuffer", py::buffer_protocol())
|
||||||
|
.def(py::init<>())
|
||||||
|
.def_readwrite("value", (int32_t DerivedBuffer::*) &DerivedBuffer::value)
|
||||||
|
.def_buffer(&DerivedBuffer::get_buffer_info);
|
||||||
|
|
||||||
|
struct BufferReadOnly {
|
||||||
|
const uint8_t value = 0;
|
||||||
|
BufferReadOnly(uint8_t value): value(value) {}
|
||||||
|
|
||||||
|
py::buffer_info get_buffer_info() {
|
||||||
|
return py::buffer_info(&value, 1);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
py::class_<BufferReadOnly>(m, "BufferReadOnly", py::buffer_protocol())
|
||||||
|
.def(py::init<uint8_t>())
|
||||||
|
.def_buffer(&BufferReadOnly::get_buffer_info);
|
||||||
|
|
||||||
|
struct BufferReadOnlySelect {
|
||||||
|
uint8_t value = 0;
|
||||||
|
bool readonly = false;
|
||||||
|
|
||||||
|
py::buffer_info get_buffer_info() {
|
||||||
|
return py::buffer_info(&value, 1, readonly);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
py::class_<BufferReadOnlySelect>(m, "BufferReadOnlySelect", py::buffer_protocol())
|
||||||
|
.def(py::init<>())
|
||||||
|
.def_readwrite("value", &BufferReadOnlySelect::value)
|
||||||
|
.def_readwrite("readonly", &BufferReadOnlySelect::readonly)
|
||||||
|
.def_buffer(&BufferReadOnlySelect::get_buffer_info);
|
||||||
|
|
||||||
|
}
|
118
3rdparty/pybind11/tests/test_buffers.py
vendored
Normal file
118
3rdparty/pybind11/tests/test_buffers.py
vendored
Normal file
@ -0,0 +1,118 @@
|
|||||||
|
import io
|
||||||
|
import struct
|
||||||
|
import sys
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
from pybind11_tests import buffers as m
|
||||||
|
from pybind11_tests import ConstructorStats
|
||||||
|
|
||||||
|
PY3 = sys.version_info[0] >= 3
|
||||||
|
|
||||||
|
pytestmark = pytest.requires_numpy
|
||||||
|
|
||||||
|
with pytest.suppress(ImportError):
|
||||||
|
import numpy as np
|
||||||
|
|
||||||
|
|
||||||
|
def test_from_python():
|
||||||
|
with pytest.raises(RuntimeError) as excinfo:
|
||||||
|
m.Matrix(np.array([1, 2, 3])) # trying to assign a 1D array
|
||||||
|
assert str(excinfo.value) == "Incompatible buffer format!"
|
||||||
|
|
||||||
|
m3 = np.array([[1, 2, 3], [4, 5, 6]]).astype(np.float32)
|
||||||
|
m4 = m.Matrix(m3)
|
||||||
|
|
||||||
|
for i in range(m4.rows()):
|
||||||
|
for j in range(m4.cols()):
|
||||||
|
assert m3[i, j] == m4[i, j]
|
||||||
|
|
||||||
|
cstats = ConstructorStats.get(m.Matrix)
|
||||||
|
assert cstats.alive() == 1
|
||||||
|
del m3, m4
|
||||||
|
assert cstats.alive() == 0
|
||||||
|
assert cstats.values() == ["2x3 matrix"]
|
||||||
|
assert cstats.copy_constructions == 0
|
||||||
|
# assert cstats.move_constructions >= 0 # Don't invoke any
|
||||||
|
assert cstats.copy_assignments == 0
|
||||||
|
assert cstats.move_assignments == 0
|
||||||
|
|
||||||
|
|
||||||
|
# PyPy: Memory leak in the "np.array(m, copy=False)" call
|
||||||
|
# https://bitbucket.org/pypy/pypy/issues/2444
|
||||||
|
@pytest.unsupported_on_pypy
|
||||||
|
def test_to_python():
|
||||||
|
mat = m.Matrix(5, 4)
|
||||||
|
assert memoryview(mat).shape == (5, 4)
|
||||||
|
|
||||||
|
assert mat[2, 3] == 0
|
||||||
|
mat[2, 3] = 4.0
|
||||||
|
mat[3, 2] = 7.0
|
||||||
|
assert mat[2, 3] == 4
|
||||||
|
assert mat[3, 2] == 7
|
||||||
|
assert struct.unpack_from('f', mat, (3 * 4 + 2) * 4) == (7, )
|
||||||
|
assert struct.unpack_from('f', mat, (2 * 4 + 3) * 4) == (4, )
|
||||||
|
|
||||||
|
mat2 = np.array(mat, copy=False)
|
||||||
|
assert mat2.shape == (5, 4)
|
||||||
|
assert abs(mat2).sum() == 11
|
||||||
|
assert mat2[2, 3] == 4 and mat2[3, 2] == 7
|
||||||
|
mat2[2, 3] = 5
|
||||||
|
assert mat2[2, 3] == 5
|
||||||
|
|
||||||
|
cstats = ConstructorStats.get(m.Matrix)
|
||||||
|
assert cstats.alive() == 1
|
||||||
|
del mat
|
||||||
|
pytest.gc_collect()
|
||||||
|
assert cstats.alive() == 1
|
||||||
|
del mat2 # holds a mat reference
|
||||||
|
pytest.gc_collect()
|
||||||
|
assert cstats.alive() == 0
|
||||||
|
assert cstats.values() == ["5x4 matrix"]
|
||||||
|
assert cstats.copy_constructions == 0
|
||||||
|
# assert cstats.move_constructions >= 0 # Don't invoke any
|
||||||
|
assert cstats.copy_assignments == 0
|
||||||
|
assert cstats.move_assignments == 0
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.unsupported_on_pypy
|
||||||
|
def test_inherited_protocol():
|
||||||
|
"""SquareMatrix is derived from Matrix and inherits the buffer protocol"""
|
||||||
|
|
||||||
|
matrix = m.SquareMatrix(5)
|
||||||
|
assert memoryview(matrix).shape == (5, 5)
|
||||||
|
assert np.asarray(matrix).shape == (5, 5)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.unsupported_on_pypy
|
||||||
|
def test_pointer_to_member_fn():
|
||||||
|
for cls in [m.Buffer, m.ConstBuffer, m.DerivedBuffer]:
|
||||||
|
buf = cls()
|
||||||
|
buf.value = 0x12345678
|
||||||
|
value = struct.unpack('i', bytearray(buf))[0]
|
||||||
|
assert value == 0x12345678
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.unsupported_on_pypy
|
||||||
|
def test_readonly_buffer():
|
||||||
|
buf = m.BufferReadOnly(0x64)
|
||||||
|
view = memoryview(buf)
|
||||||
|
assert view[0] == 0x64 if PY3 else b'd'
|
||||||
|
assert view.readonly
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.unsupported_on_pypy
|
||||||
|
def test_selective_readonly_buffer():
|
||||||
|
buf = m.BufferReadOnlySelect()
|
||||||
|
|
||||||
|
memoryview(buf)[0] = 0x64 if PY3 else b'd'
|
||||||
|
assert buf.value == 0x64
|
||||||
|
|
||||||
|
io.BytesIO(b'A').readinto(buf)
|
||||||
|
assert buf.value == ord(b'A')
|
||||||
|
|
||||||
|
buf.readonly = True
|
||||||
|
with pytest.raises(TypeError):
|
||||||
|
memoryview(buf)[0] = 0 if PY3 else b'\0'
|
||||||
|
with pytest.raises(TypeError):
|
||||||
|
io.BytesIO(b'1').readinto(buf)
|
188
3rdparty/pybind11/tests/test_builtin_casters.cpp
vendored
Normal file
188
3rdparty/pybind11/tests/test_builtin_casters.cpp
vendored
Normal file
@ -0,0 +1,188 @@
|
|||||||
|
/*
|
||||||
|
tests/test_builtin_casters.cpp -- Casters available without any additional headers
|
||||||
|
|
||||||
|
Copyright (c) 2017 Wenzel Jakob <wenzel.jakob@epfl.ch>
|
||||||
|
|
||||||
|
All rights reserved. Use of this source code is governed by a
|
||||||
|
BSD-style license that can be found in the LICENSE file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "pybind11_tests.h"
|
||||||
|
#include <pybind11/complex.h>
|
||||||
|
|
||||||
|
#if defined(_MSC_VER)
|
||||||
|
# pragma warning(push)
|
||||||
|
# pragma warning(disable: 4127) // warning C4127: Conditional expression is constant
|
||||||
|
#endif
|
||||||
|
|
||||||
|
TEST_SUBMODULE(builtin_casters, m) {
|
||||||
|
// test_simple_string
|
||||||
|
m.def("string_roundtrip", [](const char *s) { return s; });
|
||||||
|
|
||||||
|
// test_unicode_conversion
|
||||||
|
// Some test characters in utf16 and utf32 encodings. The last one (the 𝐀) contains a null byte
|
||||||
|
char32_t a32 = 0x61 /*a*/, z32 = 0x7a /*z*/, ib32 = 0x203d /*‽*/, cake32 = 0x1f382 /*🎂*/, mathbfA32 = 0x1d400 /*𝐀*/;
|
||||||
|
char16_t b16 = 0x62 /*b*/, z16 = 0x7a, ib16 = 0x203d, cake16_1 = 0xd83c, cake16_2 = 0xdf82, mathbfA16_1 = 0xd835, mathbfA16_2 = 0xdc00;
|
||||||
|
std::wstring wstr;
|
||||||
|
wstr.push_back(0x61); // a
|
||||||
|
wstr.push_back(0x2e18); // ⸘
|
||||||
|
if (sizeof(wchar_t) == 2) { wstr.push_back(mathbfA16_1); wstr.push_back(mathbfA16_2); } // 𝐀, utf16
|
||||||
|
else { wstr.push_back((wchar_t) mathbfA32); } // 𝐀, utf32
|
||||||
|
wstr.push_back(0x7a); // z
|
||||||
|
|
||||||
|
m.def("good_utf8_string", []() { return std::string((const char*)u8"Say utf8\u203d \U0001f382 \U0001d400"); }); // Say utf8‽ 🎂 𝐀
|
||||||
|
m.def("good_utf16_string", [=]() { return std::u16string({ b16, ib16, cake16_1, cake16_2, mathbfA16_1, mathbfA16_2, z16 }); }); // b‽🎂𝐀z
|
||||||
|
m.def("good_utf32_string", [=]() { return std::u32string({ a32, mathbfA32, cake32, ib32, z32 }); }); // a𝐀🎂‽z
|
||||||
|
m.def("good_wchar_string", [=]() { return wstr; }); // a‽𝐀z
|
||||||
|
m.def("bad_utf8_string", []() { return std::string("abc\xd0" "def"); });
|
||||||
|
m.def("bad_utf16_string", [=]() { return std::u16string({ b16, char16_t(0xd800), z16 }); });
|
||||||
|
// Under Python 2.7, invalid unicode UTF-32 characters don't appear to trigger UnicodeDecodeError
|
||||||
|
if (PY_MAJOR_VERSION >= 3)
|
||||||
|
m.def("bad_utf32_string", [=]() { return std::u32string({ a32, char32_t(0xd800), z32 }); });
|
||||||
|
if (PY_MAJOR_VERSION >= 3 || sizeof(wchar_t) == 2)
|
||||||
|
m.def("bad_wchar_string", [=]() { return std::wstring({ wchar_t(0x61), wchar_t(0xd800) }); });
|
||||||
|
m.def("u8_Z", []() -> char { return 'Z'; });
|
||||||
|
m.def("u8_eacute", []() -> char { return '\xe9'; });
|
||||||
|
m.def("u16_ibang", [=]() -> char16_t { return ib16; });
|
||||||
|
m.def("u32_mathbfA", [=]() -> char32_t { return mathbfA32; });
|
||||||
|
m.def("wchar_heart", []() -> wchar_t { return 0x2665; });
|
||||||
|
|
||||||
|
// test_single_char_arguments
|
||||||
|
m.attr("wchar_size") = py::cast(sizeof(wchar_t));
|
||||||
|
m.def("ord_char", [](char c) -> int { return static_cast<unsigned char>(c); });
|
||||||
|
m.def("ord_char_lv", [](char &c) -> int { return static_cast<unsigned char>(c); });
|
||||||
|
m.def("ord_char16", [](char16_t c) -> uint16_t { return c; });
|
||||||
|
m.def("ord_char16_lv", [](char16_t &c) -> uint16_t { return c; });
|
||||||
|
m.def("ord_char32", [](char32_t c) -> uint32_t { return c; });
|
||||||
|
m.def("ord_wchar", [](wchar_t c) -> int { return c; });
|
||||||
|
|
||||||
|
// test_bytes_to_string
|
||||||
|
m.def("strlen", [](char *s) { return strlen(s); });
|
||||||
|
m.def("string_length", [](std::string s) { return s.length(); });
|
||||||
|
|
||||||
|
#ifdef PYBIND11_HAS_U8STRING
|
||||||
|
m.attr("has_u8string") = true;
|
||||||
|
m.def("good_utf8_u8string", []() { return std::u8string(u8"Say utf8\u203d \U0001f382 \U0001d400"); }); // Say utf8‽ 🎂 𝐀
|
||||||
|
m.def("bad_utf8_u8string", []() { return std::u8string((const char8_t*)"abc\xd0" "def"); });
|
||||||
|
|
||||||
|
m.def("u8_char8_Z", []() -> char8_t { return u8'Z'; });
|
||||||
|
|
||||||
|
// test_single_char_arguments
|
||||||
|
m.def("ord_char8", [](char8_t c) -> int { return static_cast<unsigned char>(c); });
|
||||||
|
m.def("ord_char8_lv", [](char8_t &c) -> int { return static_cast<unsigned char>(c); });
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// test_string_view
|
||||||
|
#ifdef PYBIND11_HAS_STRING_VIEW
|
||||||
|
m.attr("has_string_view") = true;
|
||||||
|
m.def("string_view_print", [](std::string_view s) { py::print(s, s.size()); });
|
||||||
|
m.def("string_view16_print", [](std::u16string_view s) { py::print(s, s.size()); });
|
||||||
|
m.def("string_view32_print", [](std::u32string_view s) { py::print(s, s.size()); });
|
||||||
|
m.def("string_view_chars", [](std::string_view s) { py::list l; for (auto c : s) l.append((std::uint8_t) c); return l; });
|
||||||
|
m.def("string_view16_chars", [](std::u16string_view s) { py::list l; for (auto c : s) l.append((int) c); return l; });
|
||||||
|
m.def("string_view32_chars", [](std::u32string_view s) { py::list l; for (auto c : s) l.append((int) c); return l; });
|
||||||
|
m.def("string_view_return", []() { return std::string_view((const char*)u8"utf8 secret \U0001f382"); });
|
||||||
|
m.def("string_view16_return", []() { return std::u16string_view(u"utf16 secret \U0001f382"); });
|
||||||
|
m.def("string_view32_return", []() { return std::u32string_view(U"utf32 secret \U0001f382"); });
|
||||||
|
|
||||||
|
# ifdef PYBIND11_HAS_U8STRING
|
||||||
|
m.def("string_view8_print", [](std::u8string_view s) { py::print(s, s.size()); });
|
||||||
|
m.def("string_view8_chars", [](std::u8string_view s) { py::list l; for (auto c : s) l.append((std::uint8_t) c); return l; });
|
||||||
|
m.def("string_view8_return", []() { return std::u8string_view(u8"utf8 secret \U0001f382"); });
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// test_integer_casting
|
||||||
|
m.def("i32_str", [](std::int32_t v) { return std::to_string(v); });
|
||||||
|
m.def("u32_str", [](std::uint32_t v) { return std::to_string(v); });
|
||||||
|
m.def("i64_str", [](std::int64_t v) { return std::to_string(v); });
|
||||||
|
m.def("u64_str", [](std::uint64_t v) { return std::to_string(v); });
|
||||||
|
|
||||||
|
// test_tuple
|
||||||
|
m.def("pair_passthrough", [](std::pair<bool, std::string> input) {
|
||||||
|
return std::make_pair(input.second, input.first);
|
||||||
|
}, "Return a pair in reversed order");
|
||||||
|
m.def("tuple_passthrough", [](std::tuple<bool, std::string, int> input) {
|
||||||
|
return std::make_tuple(std::get<2>(input), std::get<1>(input), std::get<0>(input));
|
||||||
|
}, "Return a triple in reversed order");
|
||||||
|
m.def("empty_tuple", []() { return std::tuple<>(); });
|
||||||
|
static std::pair<RValueCaster, RValueCaster> lvpair;
|
||||||
|
static std::tuple<RValueCaster, RValueCaster, RValueCaster> lvtuple;
|
||||||
|
static std::pair<RValueCaster, std::tuple<RValueCaster, std::pair<RValueCaster, RValueCaster>>> lvnested;
|
||||||
|
m.def("rvalue_pair", []() { return std::make_pair(RValueCaster{}, RValueCaster{}); });
|
||||||
|
m.def("lvalue_pair", []() -> const decltype(lvpair) & { return lvpair; });
|
||||||
|
m.def("rvalue_tuple", []() { return std::make_tuple(RValueCaster{}, RValueCaster{}, RValueCaster{}); });
|
||||||
|
m.def("lvalue_tuple", []() -> const decltype(lvtuple) & { return lvtuple; });
|
||||||
|
m.def("rvalue_nested", []() {
|
||||||
|
return std::make_pair(RValueCaster{}, std::make_tuple(RValueCaster{}, std::make_pair(RValueCaster{}, RValueCaster{}))); });
|
||||||
|
m.def("lvalue_nested", []() -> const decltype(lvnested) & { return lvnested; });
|
||||||
|
|
||||||
|
// test_builtins_cast_return_none
|
||||||
|
m.def("return_none_string", []() -> std::string * { return nullptr; });
|
||||||
|
m.def("return_none_char", []() -> const char * { return nullptr; });
|
||||||
|
m.def("return_none_bool", []() -> bool * { return nullptr; });
|
||||||
|
m.def("return_none_int", []() -> int * { return nullptr; });
|
||||||
|
m.def("return_none_float", []() -> float * { return nullptr; });
|
||||||
|
|
||||||
|
// test_none_deferred
|
||||||
|
m.def("defer_none_cstring", [](char *) { return false; });
|
||||||
|
m.def("defer_none_cstring", [](py::none) { return true; });
|
||||||
|
m.def("defer_none_custom", [](UserType *) { return false; });
|
||||||
|
m.def("defer_none_custom", [](py::none) { return true; });
|
||||||
|
m.def("nodefer_none_void", [](void *) { return true; });
|
||||||
|
m.def("nodefer_none_void", [](py::none) { return false; });
|
||||||
|
|
||||||
|
// test_void_caster
|
||||||
|
m.def("load_nullptr_t", [](std::nullptr_t) {}); // not useful, but it should still compile
|
||||||
|
m.def("cast_nullptr_t", []() { return std::nullptr_t{}; });
|
||||||
|
|
||||||
|
// test_bool_caster
|
||||||
|
m.def("bool_passthrough", [](bool arg) { return arg; });
|
||||||
|
m.def("bool_passthrough_noconvert", [](bool arg) { return arg; }, py::arg().noconvert());
|
||||||
|
|
||||||
|
// test_reference_wrapper
|
||||||
|
m.def("refwrap_builtin", [](std::reference_wrapper<int> p) { return 10 * p.get(); });
|
||||||
|
m.def("refwrap_usertype", [](std::reference_wrapper<UserType> p) { return p.get().value(); });
|
||||||
|
// Not currently supported (std::pair caster has return-by-value cast operator);
|
||||||
|
// triggers static_assert failure.
|
||||||
|
//m.def("refwrap_pair", [](std::reference_wrapper<std::pair<int, int>>) { });
|
||||||
|
|
||||||
|
m.def("refwrap_list", [](bool copy) {
|
||||||
|
static IncType x1(1), x2(2);
|
||||||
|
py::list l;
|
||||||
|
for (auto &f : {std::ref(x1), std::ref(x2)}) {
|
||||||
|
l.append(py::cast(f, copy ? py::return_value_policy::copy
|
||||||
|
: py::return_value_policy::reference));
|
||||||
|
}
|
||||||
|
return l;
|
||||||
|
}, "copy"_a);
|
||||||
|
|
||||||
|
m.def("refwrap_iiw", [](const IncType &w) { return w.value(); });
|
||||||
|
m.def("refwrap_call_iiw", [](IncType &w, py::function f) {
|
||||||
|
py::list l;
|
||||||
|
l.append(f(std::ref(w)));
|
||||||
|
l.append(f(std::cref(w)));
|
||||||
|
IncType x(w.value());
|
||||||
|
l.append(f(std::ref(x)));
|
||||||
|
IncType y(w.value());
|
||||||
|
auto r3 = std::ref(y);
|
||||||
|
l.append(f(r3));
|
||||||
|
return l;
|
||||||
|
});
|
||||||
|
|
||||||
|
// test_complex
|
||||||
|
m.def("complex_cast", [](float x) { return "{}"_s.format(x); });
|
||||||
|
m.def("complex_cast", [](std::complex<float> x) { return "({}, {})"_s.format(x.real(), x.imag()); });
|
||||||
|
|
||||||
|
// test int vs. long (Python 2)
|
||||||
|
m.def("int_cast", []() {return (int) 42;});
|
||||||
|
m.def("long_cast", []() {return (long) 42;});
|
||||||
|
m.def("longlong_cast", []() {return ULLONG_MAX;});
|
||||||
|
|
||||||
|
/// test void* cast operator
|
||||||
|
m.def("test_void_caster", []() -> bool {
|
||||||
|
void *v = (void *) 0xabcd;
|
||||||
|
py::object o = py::cast(v);
|
||||||
|
return py::cast<void *>(o) == v;
|
||||||
|
});
|
||||||
|
}
|
385
3rdparty/pybind11/tests/test_builtin_casters.py
vendored
Normal file
385
3rdparty/pybind11/tests/test_builtin_casters.py
vendored
Normal file
@ -0,0 +1,385 @@
|
|||||||
|
# Python < 3 needs this: coding=utf-8
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
from pybind11_tests import builtin_casters as m
|
||||||
|
from pybind11_tests import UserType, IncType
|
||||||
|
|
||||||
|
|
||||||
|
def test_simple_string():
|
||||||
|
assert m.string_roundtrip("const char *") == "const char *"
|
||||||
|
|
||||||
|
|
||||||
|
def test_unicode_conversion():
|
||||||
|
"""Tests unicode conversion and error reporting."""
|
||||||
|
assert m.good_utf8_string() == u"Say utf8‽ 🎂 𝐀"
|
||||||
|
assert m.good_utf16_string() == u"b‽🎂𝐀z"
|
||||||
|
assert m.good_utf32_string() == u"a𝐀🎂‽z"
|
||||||
|
assert m.good_wchar_string() == u"a⸘𝐀z"
|
||||||
|
if hasattr(m, "has_u8string"):
|
||||||
|
assert m.good_utf8_u8string() == u"Say utf8‽ 🎂 𝐀"
|
||||||
|
|
||||||
|
with pytest.raises(UnicodeDecodeError):
|
||||||
|
m.bad_utf8_string()
|
||||||
|
|
||||||
|
with pytest.raises(UnicodeDecodeError):
|
||||||
|
m.bad_utf16_string()
|
||||||
|
|
||||||
|
# These are provided only if they actually fail (they don't when 32-bit and under Python 2.7)
|
||||||
|
if hasattr(m, "bad_utf32_string"):
|
||||||
|
with pytest.raises(UnicodeDecodeError):
|
||||||
|
m.bad_utf32_string()
|
||||||
|
if hasattr(m, "bad_wchar_string"):
|
||||||
|
with pytest.raises(UnicodeDecodeError):
|
||||||
|
m.bad_wchar_string()
|
||||||
|
if hasattr(m, "has_u8string"):
|
||||||
|
with pytest.raises(UnicodeDecodeError):
|
||||||
|
m.bad_utf8_u8string()
|
||||||
|
|
||||||
|
assert m.u8_Z() == 'Z'
|
||||||
|
assert m.u8_eacute() == u'é'
|
||||||
|
assert m.u16_ibang() == u'‽'
|
||||||
|
assert m.u32_mathbfA() == u'𝐀'
|
||||||
|
assert m.wchar_heart() == u'♥'
|
||||||
|
if hasattr(m, "has_u8string"):
|
||||||
|
assert m.u8_char8_Z() == 'Z'
|
||||||
|
|
||||||
|
|
||||||
|
def test_single_char_arguments():
|
||||||
|
"""Tests failures for passing invalid inputs to char-accepting functions"""
|
||||||
|
def toobig_message(r):
|
||||||
|
return "Character code point not in range({0:#x})".format(r)
|
||||||
|
toolong_message = "Expected a character, but multi-character string found"
|
||||||
|
|
||||||
|
assert m.ord_char(u'a') == 0x61 # simple ASCII
|
||||||
|
assert m.ord_char_lv(u'b') == 0x62
|
||||||
|
assert m.ord_char(u'é') == 0xE9 # requires 2 bytes in utf-8, but can be stuffed in a char
|
||||||
|
with pytest.raises(ValueError) as excinfo:
|
||||||
|
assert m.ord_char(u'Ā') == 0x100 # requires 2 bytes, doesn't fit in a char
|
||||||
|
assert str(excinfo.value) == toobig_message(0x100)
|
||||||
|
with pytest.raises(ValueError) as excinfo:
|
||||||
|
assert m.ord_char(u'ab')
|
||||||
|
assert str(excinfo.value) == toolong_message
|
||||||
|
|
||||||
|
assert m.ord_char16(u'a') == 0x61
|
||||||
|
assert m.ord_char16(u'é') == 0xE9
|
||||||
|
assert m.ord_char16_lv(u'ê') == 0xEA
|
||||||
|
assert m.ord_char16(u'Ā') == 0x100
|
||||||
|
assert m.ord_char16(u'‽') == 0x203d
|
||||||
|
assert m.ord_char16(u'♥') == 0x2665
|
||||||
|
assert m.ord_char16_lv(u'♡') == 0x2661
|
||||||
|
with pytest.raises(ValueError) as excinfo:
|
||||||
|
assert m.ord_char16(u'🎂') == 0x1F382 # requires surrogate pair
|
||||||
|
assert str(excinfo.value) == toobig_message(0x10000)
|
||||||
|
with pytest.raises(ValueError) as excinfo:
|
||||||
|
assert m.ord_char16(u'aa')
|
||||||
|
assert str(excinfo.value) == toolong_message
|
||||||
|
|
||||||
|
assert m.ord_char32(u'a') == 0x61
|
||||||
|
assert m.ord_char32(u'é') == 0xE9
|
||||||
|
assert m.ord_char32(u'Ā') == 0x100
|
||||||
|
assert m.ord_char32(u'‽') == 0x203d
|
||||||
|
assert m.ord_char32(u'♥') == 0x2665
|
||||||
|
assert m.ord_char32(u'🎂') == 0x1F382
|
||||||
|
with pytest.raises(ValueError) as excinfo:
|
||||||
|
assert m.ord_char32(u'aa')
|
||||||
|
assert str(excinfo.value) == toolong_message
|
||||||
|
|
||||||
|
assert m.ord_wchar(u'a') == 0x61
|
||||||
|
assert m.ord_wchar(u'é') == 0xE9
|
||||||
|
assert m.ord_wchar(u'Ā') == 0x100
|
||||||
|
assert m.ord_wchar(u'‽') == 0x203d
|
||||||
|
assert m.ord_wchar(u'♥') == 0x2665
|
||||||
|
if m.wchar_size == 2:
|
||||||
|
with pytest.raises(ValueError) as excinfo:
|
||||||
|
assert m.ord_wchar(u'🎂') == 0x1F382 # requires surrogate pair
|
||||||
|
assert str(excinfo.value) == toobig_message(0x10000)
|
||||||
|
else:
|
||||||
|
assert m.ord_wchar(u'🎂') == 0x1F382
|
||||||
|
with pytest.raises(ValueError) as excinfo:
|
||||||
|
assert m.ord_wchar(u'aa')
|
||||||
|
assert str(excinfo.value) == toolong_message
|
||||||
|
|
||||||
|
if hasattr(m, "has_u8string"):
|
||||||
|
assert m.ord_char8(u'a') == 0x61 # simple ASCII
|
||||||
|
assert m.ord_char8_lv(u'b') == 0x62
|
||||||
|
assert m.ord_char8(u'é') == 0xE9 # requires 2 bytes in utf-8, but can be stuffed in a char
|
||||||
|
with pytest.raises(ValueError) as excinfo:
|
||||||
|
assert m.ord_char8(u'Ā') == 0x100 # requires 2 bytes, doesn't fit in a char
|
||||||
|
assert str(excinfo.value) == toobig_message(0x100)
|
||||||
|
with pytest.raises(ValueError) as excinfo:
|
||||||
|
assert m.ord_char8(u'ab')
|
||||||
|
assert str(excinfo.value) == toolong_message
|
||||||
|
|
||||||
|
|
||||||
|
def test_bytes_to_string():
|
||||||
|
"""Tests the ability to pass bytes to C++ string-accepting functions. Note that this is
|
||||||
|
one-way: the only way to return bytes to Python is via the pybind11::bytes class."""
|
||||||
|
# Issue #816
|
||||||
|
import sys
|
||||||
|
byte = bytes if sys.version_info[0] < 3 else str
|
||||||
|
|
||||||
|
assert m.strlen(byte("hi")) == 2
|
||||||
|
assert m.string_length(byte("world")) == 5
|
||||||
|
assert m.string_length(byte("a\x00b")) == 3
|
||||||
|
assert m.strlen(byte("a\x00b")) == 1 # C-string limitation
|
||||||
|
|
||||||
|
# passing in a utf8 encoded string should work
|
||||||
|
assert m.string_length(u'💩'.encode("utf8")) == 4
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.skipif(not hasattr(m, "has_string_view"), reason="no <string_view>")
|
||||||
|
def test_string_view(capture):
|
||||||
|
"""Tests support for C++17 string_view arguments and return values"""
|
||||||
|
assert m.string_view_chars("Hi") == [72, 105]
|
||||||
|
assert m.string_view_chars("Hi 🎂") == [72, 105, 32, 0xf0, 0x9f, 0x8e, 0x82]
|
||||||
|
assert m.string_view16_chars("Hi 🎂") == [72, 105, 32, 0xd83c, 0xdf82]
|
||||||
|
assert m.string_view32_chars("Hi 🎂") == [72, 105, 32, 127874]
|
||||||
|
if hasattr(m, "has_u8string"):
|
||||||
|
assert m.string_view8_chars("Hi") == [72, 105]
|
||||||
|
assert m.string_view8_chars("Hi 🎂") == [72, 105, 32, 0xf0, 0x9f, 0x8e, 0x82]
|
||||||
|
|
||||||
|
assert m.string_view_return() == "utf8 secret 🎂"
|
||||||
|
assert m.string_view16_return() == "utf16 secret 🎂"
|
||||||
|
assert m.string_view32_return() == "utf32 secret 🎂"
|
||||||
|
if hasattr(m, "has_u8string"):
|
||||||
|
assert m.string_view8_return() == "utf8 secret 🎂"
|
||||||
|
|
||||||
|
with capture:
|
||||||
|
m.string_view_print("Hi")
|
||||||
|
m.string_view_print("utf8 🎂")
|
||||||
|
m.string_view16_print("utf16 🎂")
|
||||||
|
m.string_view32_print("utf32 🎂")
|
||||||
|
assert capture == """
|
||||||
|
Hi 2
|
||||||
|
utf8 🎂 9
|
||||||
|
utf16 🎂 8
|
||||||
|
utf32 🎂 7
|
||||||
|
"""
|
||||||
|
if hasattr(m, "has_u8string"):
|
||||||
|
with capture:
|
||||||
|
m.string_view8_print("Hi")
|
||||||
|
m.string_view8_print("utf8 🎂")
|
||||||
|
assert capture == """
|
||||||
|
Hi 2
|
||||||
|
utf8 🎂 9
|
||||||
|
"""
|
||||||
|
|
||||||
|
with capture:
|
||||||
|
m.string_view_print("Hi, ascii")
|
||||||
|
m.string_view_print("Hi, utf8 🎂")
|
||||||
|
m.string_view16_print("Hi, utf16 🎂")
|
||||||
|
m.string_view32_print("Hi, utf32 🎂")
|
||||||
|
assert capture == """
|
||||||
|
Hi, ascii 9
|
||||||
|
Hi, utf8 🎂 13
|
||||||
|
Hi, utf16 🎂 12
|
||||||
|
Hi, utf32 🎂 11
|
||||||
|
"""
|
||||||
|
if hasattr(m, "has_u8string"):
|
||||||
|
with capture:
|
||||||
|
m.string_view8_print("Hi, ascii")
|
||||||
|
m.string_view8_print("Hi, utf8 🎂")
|
||||||
|
assert capture == """
|
||||||
|
Hi, ascii 9
|
||||||
|
Hi, utf8 🎂 13
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
def test_integer_casting():
|
||||||
|
"""Issue #929 - out-of-range integer values shouldn't be accepted"""
|
||||||
|
import sys
|
||||||
|
assert m.i32_str(-1) == "-1"
|
||||||
|
assert m.i64_str(-1) == "-1"
|
||||||
|
assert m.i32_str(2000000000) == "2000000000"
|
||||||
|
assert m.u32_str(2000000000) == "2000000000"
|
||||||
|
if sys.version_info < (3,):
|
||||||
|
assert m.i32_str(long(-1)) == "-1" # noqa: F821 undefined name 'long'
|
||||||
|
assert m.i64_str(long(-1)) == "-1" # noqa: F821 undefined name 'long'
|
||||||
|
assert m.i64_str(long(-999999999999)) == "-999999999999" # noqa: F821 undefined name
|
||||||
|
assert m.u64_str(long(999999999999)) == "999999999999" # noqa: F821 undefined name 'long'
|
||||||
|
else:
|
||||||
|
assert m.i64_str(-999999999999) == "-999999999999"
|
||||||
|
assert m.u64_str(999999999999) == "999999999999"
|
||||||
|
|
||||||
|
with pytest.raises(TypeError) as excinfo:
|
||||||
|
m.u32_str(-1)
|
||||||
|
assert "incompatible function arguments" in str(excinfo.value)
|
||||||
|
with pytest.raises(TypeError) as excinfo:
|
||||||
|
m.u64_str(-1)
|
||||||
|
assert "incompatible function arguments" in str(excinfo.value)
|
||||||
|
with pytest.raises(TypeError) as excinfo:
|
||||||
|
m.i32_str(-3000000000)
|
||||||
|
assert "incompatible function arguments" in str(excinfo.value)
|
||||||
|
with pytest.raises(TypeError) as excinfo:
|
||||||
|
m.i32_str(3000000000)
|
||||||
|
assert "incompatible function arguments" in str(excinfo.value)
|
||||||
|
|
||||||
|
if sys.version_info < (3,):
|
||||||
|
with pytest.raises(TypeError) as excinfo:
|
||||||
|
m.u32_str(long(-1)) # noqa: F821 undefined name 'long'
|
||||||
|
assert "incompatible function arguments" in str(excinfo.value)
|
||||||
|
with pytest.raises(TypeError) as excinfo:
|
||||||
|
m.u64_str(long(-1)) # noqa: F821 undefined name 'long'
|
||||||
|
assert "incompatible function arguments" in str(excinfo.value)
|
||||||
|
|
||||||
|
|
||||||
|
def test_tuple(doc):
|
||||||
|
"""std::pair <-> tuple & std::tuple <-> tuple"""
|
||||||
|
assert m.pair_passthrough((True, "test")) == ("test", True)
|
||||||
|
assert m.tuple_passthrough((True, "test", 5)) == (5, "test", True)
|
||||||
|
# Any sequence can be cast to a std::pair or std::tuple
|
||||||
|
assert m.pair_passthrough([True, "test"]) == ("test", True)
|
||||||
|
assert m.tuple_passthrough([True, "test", 5]) == (5, "test", True)
|
||||||
|
assert m.empty_tuple() == ()
|
||||||
|
|
||||||
|
assert doc(m.pair_passthrough) == """
|
||||||
|
pair_passthrough(arg0: Tuple[bool, str]) -> Tuple[str, bool]
|
||||||
|
|
||||||
|
Return a pair in reversed order
|
||||||
|
"""
|
||||||
|
assert doc(m.tuple_passthrough) == """
|
||||||
|
tuple_passthrough(arg0: Tuple[bool, str, int]) -> Tuple[int, str, bool]
|
||||||
|
|
||||||
|
Return a triple in reversed order
|
||||||
|
"""
|
||||||
|
|
||||||
|
assert m.rvalue_pair() == ("rvalue", "rvalue")
|
||||||
|
assert m.lvalue_pair() == ("lvalue", "lvalue")
|
||||||
|
assert m.rvalue_tuple() == ("rvalue", "rvalue", "rvalue")
|
||||||
|
assert m.lvalue_tuple() == ("lvalue", "lvalue", "lvalue")
|
||||||
|
assert m.rvalue_nested() == ("rvalue", ("rvalue", ("rvalue", "rvalue")))
|
||||||
|
assert m.lvalue_nested() == ("lvalue", ("lvalue", ("lvalue", "lvalue")))
|
||||||
|
|
||||||
|
|
||||||
|
def test_builtins_cast_return_none():
|
||||||
|
"""Casters produced with PYBIND11_TYPE_CASTER() should convert nullptr to None"""
|
||||||
|
assert m.return_none_string() is None
|
||||||
|
assert m.return_none_char() is None
|
||||||
|
assert m.return_none_bool() is None
|
||||||
|
assert m.return_none_int() is None
|
||||||
|
assert m.return_none_float() is None
|
||||||
|
|
||||||
|
|
||||||
|
def test_none_deferred():
|
||||||
|
"""None passed as various argument types should defer to other overloads"""
|
||||||
|
assert not m.defer_none_cstring("abc")
|
||||||
|
assert m.defer_none_cstring(None)
|
||||||
|
assert not m.defer_none_custom(UserType())
|
||||||
|
assert m.defer_none_custom(None)
|
||||||
|
assert m.nodefer_none_void(None)
|
||||||
|
|
||||||
|
|
||||||
|
def test_void_caster():
|
||||||
|
assert m.load_nullptr_t(None) is None
|
||||||
|
assert m.cast_nullptr_t() is None
|
||||||
|
|
||||||
|
|
||||||
|
def test_reference_wrapper():
|
||||||
|
"""std::reference_wrapper for builtin and user types"""
|
||||||
|
assert m.refwrap_builtin(42) == 420
|
||||||
|
assert m.refwrap_usertype(UserType(42)) == 42
|
||||||
|
|
||||||
|
with pytest.raises(TypeError) as excinfo:
|
||||||
|
m.refwrap_builtin(None)
|
||||||
|
assert "incompatible function arguments" in str(excinfo.value)
|
||||||
|
|
||||||
|
with pytest.raises(TypeError) as excinfo:
|
||||||
|
m.refwrap_usertype(None)
|
||||||
|
assert "incompatible function arguments" in str(excinfo.value)
|
||||||
|
|
||||||
|
a1 = m.refwrap_list(copy=True)
|
||||||
|
a2 = m.refwrap_list(copy=True)
|
||||||
|
assert [x.value for x in a1] == [2, 3]
|
||||||
|
assert [x.value for x in a2] == [2, 3]
|
||||||
|
assert not a1[0] is a2[0] and not a1[1] is a2[1]
|
||||||
|
|
||||||
|
b1 = m.refwrap_list(copy=False)
|
||||||
|
b2 = m.refwrap_list(copy=False)
|
||||||
|
assert [x.value for x in b1] == [1, 2]
|
||||||
|
assert [x.value for x in b2] == [1, 2]
|
||||||
|
assert b1[0] is b2[0] and b1[1] is b2[1]
|
||||||
|
|
||||||
|
assert m.refwrap_iiw(IncType(5)) == 5
|
||||||
|
assert m.refwrap_call_iiw(IncType(10), m.refwrap_iiw) == [10, 10, 10, 10]
|
||||||
|
|
||||||
|
|
||||||
|
def test_complex_cast():
|
||||||
|
"""std::complex casts"""
|
||||||
|
assert m.complex_cast(1) == "1.0"
|
||||||
|
assert m.complex_cast(2j) == "(0.0, 2.0)"
|
||||||
|
|
||||||
|
|
||||||
|
def test_bool_caster():
|
||||||
|
"""Test bool caster implicit conversions."""
|
||||||
|
convert, noconvert = m.bool_passthrough, m.bool_passthrough_noconvert
|
||||||
|
|
||||||
|
def require_implicit(v):
|
||||||
|
pytest.raises(TypeError, noconvert, v)
|
||||||
|
|
||||||
|
def cant_convert(v):
|
||||||
|
pytest.raises(TypeError, convert, v)
|
||||||
|
|
||||||
|
# straight up bool
|
||||||
|
assert convert(True) is True
|
||||||
|
assert convert(False) is False
|
||||||
|
assert noconvert(True) is True
|
||||||
|
assert noconvert(False) is False
|
||||||
|
|
||||||
|
# None requires implicit conversion
|
||||||
|
require_implicit(None)
|
||||||
|
assert convert(None) is False
|
||||||
|
|
||||||
|
class A(object):
|
||||||
|
def __init__(self, x):
|
||||||
|
self.x = x
|
||||||
|
|
||||||
|
def __nonzero__(self):
|
||||||
|
return self.x
|
||||||
|
|
||||||
|
def __bool__(self):
|
||||||
|
return self.x
|
||||||
|
|
||||||
|
class B(object):
|
||||||
|
pass
|
||||||
|
|
||||||
|
# Arbitrary objects are not accepted
|
||||||
|
cant_convert(object())
|
||||||
|
cant_convert(B())
|
||||||
|
|
||||||
|
# Objects with __nonzero__ / __bool__ defined can be converted
|
||||||
|
require_implicit(A(True))
|
||||||
|
assert convert(A(True)) is True
|
||||||
|
assert convert(A(False)) is False
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.requires_numpy
|
||||||
|
def test_numpy_bool():
|
||||||
|
import numpy as np
|
||||||
|
convert, noconvert = m.bool_passthrough, m.bool_passthrough_noconvert
|
||||||
|
|
||||||
|
def cant_convert(v):
|
||||||
|
pytest.raises(TypeError, convert, v)
|
||||||
|
|
||||||
|
# np.bool_ is not considered implicit
|
||||||
|
assert convert(np.bool_(True)) is True
|
||||||
|
assert convert(np.bool_(False)) is False
|
||||||
|
assert noconvert(np.bool_(True)) is True
|
||||||
|
assert noconvert(np.bool_(False)) is False
|
||||||
|
cant_convert(np.zeros(2, dtype='int'))
|
||||||
|
|
||||||
|
|
||||||
|
def test_int_long():
|
||||||
|
"""In Python 2, a C++ int should return a Python int rather than long
|
||||||
|
if possible: longs are not always accepted where ints are used (such
|
||||||
|
as the argument to sys.exit()). A C++ long long is always a Python
|
||||||
|
long."""
|
||||||
|
|
||||||
|
import sys
|
||||||
|
must_be_long = type(getattr(sys, 'maxint', 1) + 1)
|
||||||
|
assert isinstance(m.int_cast(), int)
|
||||||
|
assert isinstance(m.long_cast(), int)
|
||||||
|
assert isinstance(m.longlong_cast(), must_be_long)
|
||||||
|
|
||||||
|
|
||||||
|
def test_void_caster_2():
|
||||||
|
assert m.test_void_caster()
|
100
3rdparty/pybind11/tests/test_call_policies.cpp
vendored
Normal file
100
3rdparty/pybind11/tests/test_call_policies.cpp
vendored
Normal file
@ -0,0 +1,100 @@
|
|||||||
|
/*
|
||||||
|
tests/test_call_policies.cpp -- keep_alive and call_guard
|
||||||
|
|
||||||
|
Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch>
|
||||||
|
|
||||||
|
All rights reserved. Use of this source code is governed by a
|
||||||
|
BSD-style license that can be found in the LICENSE file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "pybind11_tests.h"
|
||||||
|
|
||||||
|
struct CustomGuard {
|
||||||
|
static bool enabled;
|
||||||
|
|
||||||
|
CustomGuard() { enabled = true; }
|
||||||
|
~CustomGuard() { enabled = false; }
|
||||||
|
|
||||||
|
static const char *report_status() { return enabled ? "guarded" : "unguarded"; }
|
||||||
|
};
|
||||||
|
bool CustomGuard::enabled = false;
|
||||||
|
|
||||||
|
struct DependentGuard {
|
||||||
|
static bool enabled;
|
||||||
|
|
||||||
|
DependentGuard() { enabled = CustomGuard::enabled; }
|
||||||
|
~DependentGuard() { enabled = false; }
|
||||||
|
|
||||||
|
static const char *report_status() { return enabled ? "guarded" : "unguarded"; }
|
||||||
|
};
|
||||||
|
bool DependentGuard::enabled = false;
|
||||||
|
|
||||||
|
TEST_SUBMODULE(call_policies, m) {
|
||||||
|
// Parent/Child are used in:
|
||||||
|
// test_keep_alive_argument, test_keep_alive_return_value, test_alive_gc_derived,
|
||||||
|
// test_alive_gc_multi_derived, test_return_none, test_keep_alive_constructor
|
||||||
|
class Child {
|
||||||
|
public:
|
||||||
|
Child() { py::print("Allocating child."); }
|
||||||
|
Child(const Child &) = default;
|
||||||
|
Child(Child &&) = default;
|
||||||
|
~Child() { py::print("Releasing child."); }
|
||||||
|
};
|
||||||
|
py::class_<Child>(m, "Child")
|
||||||
|
.def(py::init<>());
|
||||||
|
|
||||||
|
class Parent {
|
||||||
|
public:
|
||||||
|
Parent() { py::print("Allocating parent."); }
|
||||||
|
~Parent() { py::print("Releasing parent."); }
|
||||||
|
void addChild(Child *) { }
|
||||||
|
Child *returnChild() { return new Child(); }
|
||||||
|
Child *returnNullChild() { return nullptr; }
|
||||||
|
};
|
||||||
|
py::class_<Parent>(m, "Parent")
|
||||||
|
.def(py::init<>())
|
||||||
|
.def(py::init([](Child *) { return new Parent(); }), py::keep_alive<1, 2>())
|
||||||
|
.def("addChild", &Parent::addChild)
|
||||||
|
.def("addChildKeepAlive", &Parent::addChild, py::keep_alive<1, 2>())
|
||||||
|
.def("returnChild", &Parent::returnChild)
|
||||||
|
.def("returnChildKeepAlive", &Parent::returnChild, py::keep_alive<1, 0>())
|
||||||
|
.def("returnNullChildKeepAliveChild", &Parent::returnNullChild, py::keep_alive<1, 0>())
|
||||||
|
.def("returnNullChildKeepAliveParent", &Parent::returnNullChild, py::keep_alive<0, 1>());
|
||||||
|
|
||||||
|
#if !defined(PYPY_VERSION)
|
||||||
|
// test_alive_gc
|
||||||
|
class ParentGC : public Parent {
|
||||||
|
public:
|
||||||
|
using Parent::Parent;
|
||||||
|
};
|
||||||
|
py::class_<ParentGC, Parent>(m, "ParentGC", py::dynamic_attr())
|
||||||
|
.def(py::init<>());
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// test_call_guard
|
||||||
|
m.def("unguarded_call", &CustomGuard::report_status);
|
||||||
|
m.def("guarded_call", &CustomGuard::report_status, py::call_guard<CustomGuard>());
|
||||||
|
|
||||||
|
m.def("multiple_guards_correct_order", []() {
|
||||||
|
return CustomGuard::report_status() + std::string(" & ") + DependentGuard::report_status();
|
||||||
|
}, py::call_guard<CustomGuard, DependentGuard>());
|
||||||
|
|
||||||
|
m.def("multiple_guards_wrong_order", []() {
|
||||||
|
return DependentGuard::report_status() + std::string(" & ") + CustomGuard::report_status();
|
||||||
|
}, py::call_guard<DependentGuard, CustomGuard>());
|
||||||
|
|
||||||
|
#if defined(WITH_THREAD) && !defined(PYPY_VERSION)
|
||||||
|
// `py::call_guard<py::gil_scoped_release>()` should work in PyPy as well,
|
||||||
|
// but it's unclear how to test it without `PyGILState_GetThisThreadState`.
|
||||||
|
auto report_gil_status = []() {
|
||||||
|
auto is_gil_held = false;
|
||||||
|
if (auto tstate = py::detail::get_thread_state_unchecked())
|
||||||
|
is_gil_held = (tstate == PyGILState_GetThisThreadState());
|
||||||
|
|
||||||
|
return is_gil_held ? "GIL held" : "GIL released";
|
||||||
|
};
|
||||||
|
|
||||||
|
m.def("with_gil", report_gil_status);
|
||||||
|
m.def("without_gil", report_gil_status, py::call_guard<py::gil_scoped_release>());
|
||||||
|
#endif
|
||||||
|
}
|
187
3rdparty/pybind11/tests/test_call_policies.py
vendored
Normal file
187
3rdparty/pybind11/tests/test_call_policies.py
vendored
Normal file
@ -0,0 +1,187 @@
|
|||||||
|
import pytest
|
||||||
|
from pybind11_tests import call_policies as m
|
||||||
|
from pybind11_tests import ConstructorStats
|
||||||
|
|
||||||
|
|
||||||
|
def test_keep_alive_argument(capture):
|
||||||
|
n_inst = ConstructorStats.detail_reg_inst()
|
||||||
|
with capture:
|
||||||
|
p = m.Parent()
|
||||||
|
assert capture == "Allocating parent."
|
||||||
|
with capture:
|
||||||
|
p.addChild(m.Child())
|
||||||
|
assert ConstructorStats.detail_reg_inst() == n_inst + 1
|
||||||
|
assert capture == """
|
||||||
|
Allocating child.
|
||||||
|
Releasing child.
|
||||||
|
"""
|
||||||
|
with capture:
|
||||||
|
del p
|
||||||
|
assert ConstructorStats.detail_reg_inst() == n_inst
|
||||||
|
assert capture == "Releasing parent."
|
||||||
|
|
||||||
|
with capture:
|
||||||
|
p = m.Parent()
|
||||||
|
assert capture == "Allocating parent."
|
||||||
|
with capture:
|
||||||
|
p.addChildKeepAlive(m.Child())
|
||||||
|
assert ConstructorStats.detail_reg_inst() == n_inst + 2
|
||||||
|
assert capture == "Allocating child."
|
||||||
|
with capture:
|
||||||
|
del p
|
||||||
|
assert ConstructorStats.detail_reg_inst() == n_inst
|
||||||
|
assert capture == """
|
||||||
|
Releasing parent.
|
||||||
|
Releasing child.
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
def test_keep_alive_return_value(capture):
|
||||||
|
n_inst = ConstructorStats.detail_reg_inst()
|
||||||
|
with capture:
|
||||||
|
p = m.Parent()
|
||||||
|
assert capture == "Allocating parent."
|
||||||
|
with capture:
|
||||||
|
p.returnChild()
|
||||||
|
assert ConstructorStats.detail_reg_inst() == n_inst + 1
|
||||||
|
assert capture == """
|
||||||
|
Allocating child.
|
||||||
|
Releasing child.
|
||||||
|
"""
|
||||||
|
with capture:
|
||||||
|
del p
|
||||||
|
assert ConstructorStats.detail_reg_inst() == n_inst
|
||||||
|
assert capture == "Releasing parent."
|
||||||
|
|
||||||
|
with capture:
|
||||||
|
p = m.Parent()
|
||||||
|
assert capture == "Allocating parent."
|
||||||
|
with capture:
|
||||||
|
p.returnChildKeepAlive()
|
||||||
|
assert ConstructorStats.detail_reg_inst() == n_inst + 2
|
||||||
|
assert capture == "Allocating child."
|
||||||
|
with capture:
|
||||||
|
del p
|
||||||
|
assert ConstructorStats.detail_reg_inst() == n_inst
|
||||||
|
assert capture == """
|
||||||
|
Releasing parent.
|
||||||
|
Releasing child.
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
# https://bitbucket.org/pypy/pypy/issues/2447
|
||||||
|
@pytest.unsupported_on_pypy
|
||||||
|
def test_alive_gc(capture):
|
||||||
|
n_inst = ConstructorStats.detail_reg_inst()
|
||||||
|
p = m.ParentGC()
|
||||||
|
p.addChildKeepAlive(m.Child())
|
||||||
|
assert ConstructorStats.detail_reg_inst() == n_inst + 2
|
||||||
|
lst = [p]
|
||||||
|
lst.append(lst) # creates a circular reference
|
||||||
|
with capture:
|
||||||
|
del p, lst
|
||||||
|
assert ConstructorStats.detail_reg_inst() == n_inst
|
||||||
|
assert capture == """
|
||||||
|
Releasing parent.
|
||||||
|
Releasing child.
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
def test_alive_gc_derived(capture):
|
||||||
|
class Derived(m.Parent):
|
||||||
|
pass
|
||||||
|
|
||||||
|
n_inst = ConstructorStats.detail_reg_inst()
|
||||||
|
p = Derived()
|
||||||
|
p.addChildKeepAlive(m.Child())
|
||||||
|
assert ConstructorStats.detail_reg_inst() == n_inst + 2
|
||||||
|
lst = [p]
|
||||||
|
lst.append(lst) # creates a circular reference
|
||||||
|
with capture:
|
||||||
|
del p, lst
|
||||||
|
assert ConstructorStats.detail_reg_inst() == n_inst
|
||||||
|
assert capture == """
|
||||||
|
Releasing parent.
|
||||||
|
Releasing child.
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
def test_alive_gc_multi_derived(capture):
|
||||||
|
class Derived(m.Parent, m.Child):
|
||||||
|
def __init__(self):
|
||||||
|
m.Parent.__init__(self)
|
||||||
|
m.Child.__init__(self)
|
||||||
|
|
||||||
|
n_inst = ConstructorStats.detail_reg_inst()
|
||||||
|
p = Derived()
|
||||||
|
p.addChildKeepAlive(m.Child())
|
||||||
|
# +3 rather than +2 because Derived corresponds to two registered instances
|
||||||
|
assert ConstructorStats.detail_reg_inst() == n_inst + 3
|
||||||
|
lst = [p]
|
||||||
|
lst.append(lst) # creates a circular reference
|
||||||
|
with capture:
|
||||||
|
del p, lst
|
||||||
|
assert ConstructorStats.detail_reg_inst() == n_inst
|
||||||
|
assert capture == """
|
||||||
|
Releasing parent.
|
||||||
|
Releasing child.
|
||||||
|
Releasing child.
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
def test_return_none(capture):
|
||||||
|
n_inst = ConstructorStats.detail_reg_inst()
|
||||||
|
with capture:
|
||||||
|
p = m.Parent()
|
||||||
|
assert capture == "Allocating parent."
|
||||||
|
with capture:
|
||||||
|
p.returnNullChildKeepAliveChild()
|
||||||
|
assert ConstructorStats.detail_reg_inst() == n_inst + 1
|
||||||
|
assert capture == ""
|
||||||
|
with capture:
|
||||||
|
del p
|
||||||
|
assert ConstructorStats.detail_reg_inst() == n_inst
|
||||||
|
assert capture == "Releasing parent."
|
||||||
|
|
||||||
|
with capture:
|
||||||
|
p = m.Parent()
|
||||||
|
assert capture == "Allocating parent."
|
||||||
|
with capture:
|
||||||
|
p.returnNullChildKeepAliveParent()
|
||||||
|
assert ConstructorStats.detail_reg_inst() == n_inst + 1
|
||||||
|
assert capture == ""
|
||||||
|
with capture:
|
||||||
|
del p
|
||||||
|
assert ConstructorStats.detail_reg_inst() == n_inst
|
||||||
|
assert capture == "Releasing parent."
|
||||||
|
|
||||||
|
|
||||||
|
def test_keep_alive_constructor(capture):
|
||||||
|
n_inst = ConstructorStats.detail_reg_inst()
|
||||||
|
|
||||||
|
with capture:
|
||||||
|
p = m.Parent(m.Child())
|
||||||
|
assert ConstructorStats.detail_reg_inst() == n_inst + 2
|
||||||
|
assert capture == """
|
||||||
|
Allocating child.
|
||||||
|
Allocating parent.
|
||||||
|
"""
|
||||||
|
with capture:
|
||||||
|
del p
|
||||||
|
assert ConstructorStats.detail_reg_inst() == n_inst
|
||||||
|
assert capture == """
|
||||||
|
Releasing parent.
|
||||||
|
Releasing child.
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
def test_call_guard():
|
||||||
|
assert m.unguarded_call() == "unguarded"
|
||||||
|
assert m.guarded_call() == "guarded"
|
||||||
|
|
||||||
|
assert m.multiple_guards_correct_order() == "guarded & guarded"
|
||||||
|
assert m.multiple_guards_wrong_order() == "unguarded & guarded"
|
||||||
|
|
||||||
|
if hasattr(m, "with_gil"):
|
||||||
|
assert m.with_gil() == "GIL held"
|
||||||
|
assert m.without_gil() == "GIL released"
|
168
3rdparty/pybind11/tests/test_callbacks.cpp
vendored
Normal file
168
3rdparty/pybind11/tests/test_callbacks.cpp
vendored
Normal file
@ -0,0 +1,168 @@
|
|||||||
|
/*
|
||||||
|
tests/test_callbacks.cpp -- callbacks
|
||||||
|
|
||||||
|
Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch>
|
||||||
|
|
||||||
|
All rights reserved. Use of this source code is governed by a
|
||||||
|
BSD-style license that can be found in the LICENSE file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "pybind11_tests.h"
|
||||||
|
#include "constructor_stats.h"
|
||||||
|
#include <pybind11/functional.h>
|
||||||
|
#include <thread>
|
||||||
|
|
||||||
|
|
||||||
|
int dummy_function(int i) { return i + 1; }
|
||||||
|
|
||||||
|
TEST_SUBMODULE(callbacks, m) {
|
||||||
|
// test_callbacks, test_function_signatures
|
||||||
|
m.def("test_callback1", [](py::object func) { return func(); });
|
||||||
|
m.def("test_callback2", [](py::object func) { return func("Hello", 'x', true, 5); });
|
||||||
|
m.def("test_callback3", [](const std::function<int(int)> &func) {
|
||||||
|
return "func(43) = " + std::to_string(func(43)); });
|
||||||
|
m.def("test_callback4", []() -> std::function<int(int)> { return [](int i) { return i+1; }; });
|
||||||
|
m.def("test_callback5", []() {
|
||||||
|
return py::cpp_function([](int i) { return i+1; }, py::arg("number"));
|
||||||
|
});
|
||||||
|
|
||||||
|
// test_keyword_args_and_generalized_unpacking
|
||||||
|
m.def("test_tuple_unpacking", [](py::function f) {
|
||||||
|
auto t1 = py::make_tuple(2, 3);
|
||||||
|
auto t2 = py::make_tuple(5, 6);
|
||||||
|
return f("positional", 1, *t1, 4, *t2);
|
||||||
|
});
|
||||||
|
|
||||||
|
m.def("test_dict_unpacking", [](py::function f) {
|
||||||
|
auto d1 = py::dict("key"_a="value", "a"_a=1);
|
||||||
|
auto d2 = py::dict();
|
||||||
|
auto d3 = py::dict("b"_a=2);
|
||||||
|
return f("positional", 1, **d1, **d2, **d3);
|
||||||
|
});
|
||||||
|
|
||||||
|
m.def("test_keyword_args", [](py::function f) {
|
||||||
|
return f("x"_a=10, "y"_a=20);
|
||||||
|
});
|
||||||
|
|
||||||
|
m.def("test_unpacking_and_keywords1", [](py::function f) {
|
||||||
|
auto args = py::make_tuple(2);
|
||||||
|
auto kwargs = py::dict("d"_a=4);
|
||||||
|
return f(1, *args, "c"_a=3, **kwargs);
|
||||||
|
});
|
||||||
|
|
||||||
|
m.def("test_unpacking_and_keywords2", [](py::function f) {
|
||||||
|
auto kwargs1 = py::dict("a"_a=1);
|
||||||
|
auto kwargs2 = py::dict("c"_a=3, "d"_a=4);
|
||||||
|
return f("positional", *py::make_tuple(1), 2, *py::make_tuple(3, 4), 5,
|
||||||
|
"key"_a="value", **kwargs1, "b"_a=2, **kwargs2, "e"_a=5);
|
||||||
|
});
|
||||||
|
|
||||||
|
m.def("test_unpacking_error1", [](py::function f) {
|
||||||
|
auto kwargs = py::dict("x"_a=3);
|
||||||
|
return f("x"_a=1, "y"_a=2, **kwargs); // duplicate ** after keyword
|
||||||
|
});
|
||||||
|
|
||||||
|
m.def("test_unpacking_error2", [](py::function f) {
|
||||||
|
auto kwargs = py::dict("x"_a=3);
|
||||||
|
return f(**kwargs, "x"_a=1); // duplicate keyword after **
|
||||||
|
});
|
||||||
|
|
||||||
|
m.def("test_arg_conversion_error1", [](py::function f) {
|
||||||
|
f(234, UnregisteredType(), "kw"_a=567);
|
||||||
|
});
|
||||||
|
|
||||||
|
m.def("test_arg_conversion_error2", [](py::function f) {
|
||||||
|
f(234, "expected_name"_a=UnregisteredType(), "kw"_a=567);
|
||||||
|
});
|
||||||
|
|
||||||
|
// test_lambda_closure_cleanup
|
||||||
|
struct Payload {
|
||||||
|
Payload() { print_default_created(this); }
|
||||||
|
~Payload() { print_destroyed(this); }
|
||||||
|
Payload(const Payload &) { print_copy_created(this); }
|
||||||
|
Payload(Payload &&) { print_move_created(this); }
|
||||||
|
};
|
||||||
|
// Export the payload constructor statistics for testing purposes:
|
||||||
|
m.def("payload_cstats", &ConstructorStats::get<Payload>);
|
||||||
|
/* Test cleanup of lambda closure */
|
||||||
|
m.def("test_cleanup", []() -> std::function<void(void)> {
|
||||||
|
Payload p;
|
||||||
|
|
||||||
|
return [p]() {
|
||||||
|
/* p should be cleaned up when the returned function is garbage collected */
|
||||||
|
(void) p;
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
// test_cpp_function_roundtrip
|
||||||
|
/* Test if passing a function pointer from C++ -> Python -> C++ yields the original pointer */
|
||||||
|
m.def("dummy_function", &dummy_function);
|
||||||
|
m.def("dummy_function2", [](int i, int j) { return i + j; });
|
||||||
|
m.def("roundtrip", [](std::function<int(int)> f, bool expect_none = false) {
|
||||||
|
if (expect_none && f)
|
||||||
|
throw std::runtime_error("Expected None to be converted to empty std::function");
|
||||||
|
return f;
|
||||||
|
}, py::arg("f"), py::arg("expect_none")=false);
|
||||||
|
m.def("test_dummy_function", [](const std::function<int(int)> &f) -> std::string {
|
||||||
|
using fn_type = int (*)(int);
|
||||||
|
auto result = f.target<fn_type>();
|
||||||
|
if (!result) {
|
||||||
|
auto r = f(1);
|
||||||
|
return "can't convert to function pointer: eval(1) = " + std::to_string(r);
|
||||||
|
} else if (*result == dummy_function) {
|
||||||
|
auto r = (*result)(1);
|
||||||
|
return "matches dummy_function: eval(1) = " + std::to_string(r);
|
||||||
|
} else {
|
||||||
|
return "argument does NOT match dummy_function. This should never happen!";
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
class AbstractBase { public: virtual unsigned int func() = 0; };
|
||||||
|
m.def("func_accepting_func_accepting_base", [](std::function<double(AbstractBase&)>) { });
|
||||||
|
|
||||||
|
struct MovableObject {
|
||||||
|
bool valid = true;
|
||||||
|
|
||||||
|
MovableObject() = default;
|
||||||
|
MovableObject(const MovableObject &) = default;
|
||||||
|
MovableObject &operator=(const MovableObject &) = default;
|
||||||
|
MovableObject(MovableObject &&o) : valid(o.valid) { o.valid = false; }
|
||||||
|
MovableObject &operator=(MovableObject &&o) {
|
||||||
|
valid = o.valid;
|
||||||
|
o.valid = false;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
py::class_<MovableObject>(m, "MovableObject");
|
||||||
|
|
||||||
|
// test_movable_object
|
||||||
|
m.def("callback_with_movable", [](std::function<void(MovableObject &)> f) {
|
||||||
|
auto x = MovableObject();
|
||||||
|
f(x); // lvalue reference shouldn't move out object
|
||||||
|
return x.valid; // must still return `true`
|
||||||
|
});
|
||||||
|
|
||||||
|
// test_bound_method_callback
|
||||||
|
struct CppBoundMethodTest {};
|
||||||
|
py::class_<CppBoundMethodTest>(m, "CppBoundMethodTest")
|
||||||
|
.def(py::init<>())
|
||||||
|
.def("triple", [](CppBoundMethodTest &, int val) { return 3 * val; });
|
||||||
|
|
||||||
|
// test async Python callbacks
|
||||||
|
using callback_f = std::function<void(int)>;
|
||||||
|
m.def("test_async_callback", [](callback_f f, py::list work) {
|
||||||
|
// make detached thread that calls `f` with piece of work after a little delay
|
||||||
|
auto start_f = [f](int j) {
|
||||||
|
auto invoke_f = [f, j] {
|
||||||
|
std::this_thread::sleep_for(std::chrono::milliseconds(50));
|
||||||
|
f(j);
|
||||||
|
};
|
||||||
|
auto t = std::thread(std::move(invoke_f));
|
||||||
|
t.detach();
|
||||||
|
};
|
||||||
|
|
||||||
|
// spawn worker threads
|
||||||
|
for (auto i : work)
|
||||||
|
start_f(py::cast<int>(i));
|
||||||
|
});
|
||||||
|
}
|
136
3rdparty/pybind11/tests/test_callbacks.py
vendored
Normal file
136
3rdparty/pybind11/tests/test_callbacks.py
vendored
Normal file
@ -0,0 +1,136 @@
|
|||||||
|
import pytest
|
||||||
|
from pybind11_tests import callbacks as m
|
||||||
|
from threading import Thread
|
||||||
|
|
||||||
|
|
||||||
|
def test_callbacks():
|
||||||
|
from functools import partial
|
||||||
|
|
||||||
|
def func1():
|
||||||
|
return "func1"
|
||||||
|
|
||||||
|
def func2(a, b, c, d):
|
||||||
|
return "func2", a, b, c, d
|
||||||
|
|
||||||
|
def func3(a):
|
||||||
|
return "func3({})".format(a)
|
||||||
|
|
||||||
|
assert m.test_callback1(func1) == "func1"
|
||||||
|
assert m.test_callback2(func2) == ("func2", "Hello", "x", True, 5)
|
||||||
|
assert m.test_callback1(partial(func2, 1, 2, 3, 4)) == ("func2", 1, 2, 3, 4)
|
||||||
|
assert m.test_callback1(partial(func3, "partial")) == "func3(partial)"
|
||||||
|
assert m.test_callback3(lambda i: i + 1) == "func(43) = 44"
|
||||||
|
|
||||||
|
f = m.test_callback4()
|
||||||
|
assert f(43) == 44
|
||||||
|
f = m.test_callback5()
|
||||||
|
assert f(number=43) == 44
|
||||||
|
|
||||||
|
|
||||||
|
def test_bound_method_callback():
|
||||||
|
# Bound Python method:
|
||||||
|
class MyClass:
|
||||||
|
def double(self, val):
|
||||||
|
return 2 * val
|
||||||
|
|
||||||
|
z = MyClass()
|
||||||
|
assert m.test_callback3(z.double) == "func(43) = 86"
|
||||||
|
|
||||||
|
z = m.CppBoundMethodTest()
|
||||||
|
assert m.test_callback3(z.triple) == "func(43) = 129"
|
||||||
|
|
||||||
|
|
||||||
|
def test_keyword_args_and_generalized_unpacking():
|
||||||
|
|
||||||
|
def f(*args, **kwargs):
|
||||||
|
return args, kwargs
|
||||||
|
|
||||||
|
assert m.test_tuple_unpacking(f) == (("positional", 1, 2, 3, 4, 5, 6), {})
|
||||||
|
assert m.test_dict_unpacking(f) == (("positional", 1), {"key": "value", "a": 1, "b": 2})
|
||||||
|
assert m.test_keyword_args(f) == ((), {"x": 10, "y": 20})
|
||||||
|
assert m.test_unpacking_and_keywords1(f) == ((1, 2), {"c": 3, "d": 4})
|
||||||
|
assert m.test_unpacking_and_keywords2(f) == (
|
||||||
|
("positional", 1, 2, 3, 4, 5),
|
||||||
|
{"key": "value", "a": 1, "b": 2, "c": 3, "d": 4, "e": 5}
|
||||||
|
)
|
||||||
|
|
||||||
|
with pytest.raises(TypeError) as excinfo:
|
||||||
|
m.test_unpacking_error1(f)
|
||||||
|
assert "Got multiple values for keyword argument" in str(excinfo.value)
|
||||||
|
|
||||||
|
with pytest.raises(TypeError) as excinfo:
|
||||||
|
m.test_unpacking_error2(f)
|
||||||
|
assert "Got multiple values for keyword argument" in str(excinfo.value)
|
||||||
|
|
||||||
|
with pytest.raises(RuntimeError) as excinfo:
|
||||||
|
m.test_arg_conversion_error1(f)
|
||||||
|
assert "Unable to convert call argument" in str(excinfo.value)
|
||||||
|
|
||||||
|
with pytest.raises(RuntimeError) as excinfo:
|
||||||
|
m.test_arg_conversion_error2(f)
|
||||||
|
assert "Unable to convert call argument" in str(excinfo.value)
|
||||||
|
|
||||||
|
|
||||||
|
def test_lambda_closure_cleanup():
|
||||||
|
m.test_cleanup()
|
||||||
|
cstats = m.payload_cstats()
|
||||||
|
assert cstats.alive() == 0
|
||||||
|
assert cstats.copy_constructions == 1
|
||||||
|
assert cstats.move_constructions >= 1
|
||||||
|
|
||||||
|
|
||||||
|
def test_cpp_function_roundtrip():
|
||||||
|
"""Test if passing a function pointer from C++ -> Python -> C++ yields the original pointer"""
|
||||||
|
|
||||||
|
assert m.test_dummy_function(m.dummy_function) == "matches dummy_function: eval(1) = 2"
|
||||||
|
assert (m.test_dummy_function(m.roundtrip(m.dummy_function)) ==
|
||||||
|
"matches dummy_function: eval(1) = 2")
|
||||||
|
assert m.roundtrip(None, expect_none=True) is None
|
||||||
|
assert (m.test_dummy_function(lambda x: x + 2) ==
|
||||||
|
"can't convert to function pointer: eval(1) = 3")
|
||||||
|
|
||||||
|
with pytest.raises(TypeError) as excinfo:
|
||||||
|
m.test_dummy_function(m.dummy_function2)
|
||||||
|
assert "incompatible function arguments" in str(excinfo.value)
|
||||||
|
|
||||||
|
with pytest.raises(TypeError) as excinfo:
|
||||||
|
m.test_dummy_function(lambda x, y: x + y)
|
||||||
|
assert any(s in str(excinfo.value) for s in ("missing 1 required positional argument",
|
||||||
|
"takes exactly 2 arguments"))
|
||||||
|
|
||||||
|
|
||||||
|
def test_function_signatures(doc):
|
||||||
|
assert doc(m.test_callback3) == "test_callback3(arg0: Callable[[int], int]) -> str"
|
||||||
|
assert doc(m.test_callback4) == "test_callback4() -> Callable[[int], int]"
|
||||||
|
|
||||||
|
|
||||||
|
def test_movable_object():
|
||||||
|
assert m.callback_with_movable(lambda _: None) is True
|
||||||
|
|
||||||
|
|
||||||
|
def test_async_callbacks():
|
||||||
|
# serves as state for async callback
|
||||||
|
class Item:
|
||||||
|
def __init__(self, value):
|
||||||
|
self.value = value
|
||||||
|
|
||||||
|
res = []
|
||||||
|
|
||||||
|
# generate stateful lambda that will store result in `res`
|
||||||
|
def gen_f():
|
||||||
|
s = Item(3)
|
||||||
|
return lambda j: res.append(s.value + j)
|
||||||
|
|
||||||
|
# do some work async
|
||||||
|
work = [1, 2, 3, 4]
|
||||||
|
m.test_async_callback(gen_f(), work)
|
||||||
|
# wait until work is done
|
||||||
|
from time import sleep
|
||||||
|
sleep(0.5)
|
||||||
|
assert sum(res) == sum([x + 3 for x in work])
|
||||||
|
|
||||||
|
|
||||||
|
def test_async_async_callbacks():
|
||||||
|
t = Thread(target=test_async_callbacks)
|
||||||
|
t.start()
|
||||||
|
t.join()
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user