Spaces:
Sleeping
Sleeping
91375bc0419165a4db69ee74fb0758b2f667b52d941faae0febac6e2dbac0848
Browse files- third-party/DPVO/Pangolin/components/pango_python/pybind11/LICENSE +29 -0
- third-party/DPVO/Pangolin/components/pango_python/pybind11/MANIFEST.in +6 -0
- third-party/DPVO/Pangolin/components/pango_python/pybind11/README.rst +178 -0
- third-party/DPVO/Pangolin/components/pango_python/pybind11/include/pybind11/detail/internals.h +365 -0
- third-party/DPVO/Pangolin/components/pango_python/pybind11/include/pybind11/detail/type_caster_base.h +950 -0
- third-party/DPVO/Pangolin/components/pango_python/pybind11/include/pybind11/detail/typeid.h +55 -0
- third-party/DPVO/Pangolin/components/pango_python/pybind11/include/pybind11/eigen.h +604 -0
- third-party/DPVO/Pangolin/components/pango_python/pybind11/include/pybind11/embed.h +201 -0
- third-party/DPVO/Pangolin/components/pango_python/pybind11/include/pybind11/eval.h +154 -0
- third-party/DPVO/Pangolin/components/pango_python/pybind11/include/pybind11/functional.h +117 -0
- third-party/DPVO/Pangolin/components/pango_python/pybind11/include/pybind11/gil.h +193 -0
- third-party/DPVO/Pangolin/components/pango_python/pybind11/include/pybind11/iostream.h +273 -0
- third-party/DPVO/Pangolin/components/pango_python/pybind11/include/pybind11/numpy.h +1708 -0
- third-party/DPVO/Pangolin/components/pango_python/pybind11/include/pybind11/operators.h +173 -0
- third-party/DPVO/Pangolin/components/pango_python/pybind11/include/pybind11/options.h +65 -0
- third-party/DPVO/Pangolin/components/pango_python/pybind11/include/pybind11/pybind11.h +0 -0
- third-party/DPVO/Pangolin/components/pango_python/pybind11/include/pybind11/pytypes.h +1765 -0
- third-party/DPVO/Pangolin/components/pango_python/pybind11/include/pybind11/stl.h +396 -0
- third-party/DPVO/Pangolin/components/pango_python/pybind11/include/pybind11/stl/filesystem.h +103 -0
- third-party/DPVO/Pangolin/components/pango_python/pybind11/include/pybind11/stl_bind.h +675 -0
- third-party/DPVO/Pangolin/components/pango_python/pybind11/noxfile.py +87 -0
- third-party/DPVO/Pangolin/components/pango_python/pybind11/pybind11/__init__.py +12 -0
- third-party/DPVO/Pangolin/components/pango_python/pybind11/pybind11/__main__.py +52 -0
- third-party/DPVO/Pangolin/components/pango_python/pybind11/pybind11/_version.py +12 -0
- third-party/DPVO/Pangolin/components/pango_python/pybind11/pybind11/_version.pyi +6 -0
- third-party/DPVO/Pangolin/components/pango_python/pybind11/pybind11/commands.py +22 -0
- third-party/DPVO/Pangolin/components/pango_python/pybind11/pybind11/py.typed +0 -0
- third-party/DPVO/Pangolin/components/pango_python/pybind11/pybind11/setup_helpers.py +482 -0
- third-party/DPVO/Pangolin/components/pango_python/pybind11/pybind11/setup_helpers.pyi +64 -0
- third-party/DPVO/Pangolin/components/pango_python/pybind11/pyproject.toml +35 -0
- third-party/DPVO/Pangolin/components/pango_python/pybind11/setup.cfg +56 -0
- third-party/DPVO/Pangolin/components/pango_python/pybind11/setup.py +155 -0
- third-party/DPVO/Pangolin/components/pango_python/pybind11/tests/CMakeLists.txt +495 -0
- third-party/DPVO/Pangolin/components/pango_python/pybind11/tests/conftest.py +208 -0
- third-party/DPVO/Pangolin/components/pango_python/pybind11/tests/constructor_stats.h +275 -0
- third-party/DPVO/Pangolin/components/pango_python/pybind11/tests/cross_module_gil_utils.cpp +73 -0
- third-party/DPVO/Pangolin/components/pango_python/pybind11/tests/env.py +33 -0
- third-party/DPVO/Pangolin/components/pango_python/pybind11/tests/extra_python_package/pytest.ini +0 -0
- third-party/DPVO/Pangolin/components/pango_python/pybind11/tests/extra_python_package/test_files.py +279 -0
- third-party/DPVO/Pangolin/components/pango_python/pybind11/tests/extra_setuptools/pytest.ini +0 -0
- third-party/DPVO/Pangolin/components/pango_python/pybind11/tests/extra_setuptools/test_setuphelper.py +143 -0
- third-party/DPVO/Pangolin/components/pango_python/pybind11/tests/local_bindings.h +66 -0
- third-party/DPVO/Pangolin/components/pango_python/pybind11/tests/object.h +175 -0
- third-party/DPVO/Pangolin/components/pango_python/pybind11/tests/pybind11_cross_module_tests.cpp +137 -0
- third-party/DPVO/Pangolin/components/pango_python/pybind11/tests/pybind11_tests.cpp +91 -0
- third-party/DPVO/Pangolin/components/pango_python/pybind11/tests/pybind11_tests.h +89 -0
- third-party/DPVO/Pangolin/components/pango_python/pybind11/tests/pytest.ini +19 -0
- third-party/DPVO/Pangolin/components/pango_python/pybind11/tests/requirements.txt +12 -0
- third-party/DPVO/Pangolin/components/pango_python/pybind11/tests/test_async.cpp +26 -0
- third-party/DPVO/Pangolin/components/pango_python/pybind11/tests/test_async.py +25 -0
third-party/DPVO/Pangolin/components/pango_python/pybind11/LICENSE
ADDED
@@ -0,0 +1,29 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
Copyright (c) 2016 Wenzel Jakob <[email protected]>, All rights reserved.
|
2 |
+
|
3 |
+
Redistribution and use in source and binary forms, with or without
|
4 |
+
modification, are permitted provided that the following conditions are met:
|
5 |
+
|
6 |
+
1. Redistributions of source code must retain the above copyright notice, this
|
7 |
+
list of conditions and the following disclaimer.
|
8 |
+
|
9 |
+
2. Redistributions in binary form must reproduce the above copyright notice,
|
10 |
+
this list of conditions and the following disclaimer in the documentation
|
11 |
+
and/or other materials provided with the distribution.
|
12 |
+
|
13 |
+
3. Neither the name of the copyright holder nor the names of its contributors
|
14 |
+
may be used to endorse or promote products derived from this software
|
15 |
+
without specific prior written permission.
|
16 |
+
|
17 |
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
18 |
+
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
19 |
+
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
20 |
+
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
21 |
+
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
22 |
+
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
23 |
+
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
24 |
+
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
25 |
+
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
26 |
+
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
27 |
+
|
28 |
+
Please also refer to the file .github/CONTRIBUTING.md, which clarifies licensing of
|
29 |
+
external contributions to this project including patches, pull requests, etc.
|
third-party/DPVO/Pangolin/components/pango_python/pybind11/MANIFEST.in
ADDED
@@ -0,0 +1,6 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
recursive-include pybind11/include/pybind11 *.h
|
2 |
+
recursive-include pybind11 *.py
|
3 |
+
recursive-include pybind11 py.typed
|
4 |
+
recursive-include pybind11 *.pyi
|
5 |
+
include pybind11/share/cmake/pybind11/*.cmake
|
6 |
+
include LICENSE README.rst pyproject.toml setup.py setup.cfg
|
third-party/DPVO/Pangolin/components/pango_python/pybind11/README.rst
ADDED
@@ -0,0 +1,178 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
.. figure:: https://github.com/pybind/pybind11/raw/master/docs/pybind11-logo.png
|
2 |
+
:alt: pybind11 logo
|
3 |
+
|
4 |
+
**pybind11 — Seamless operability between C++11 and Python**
|
5 |
+
|
6 |
+
|Latest Documentation Status| |Stable Documentation Status| |Gitter chat| |CI| |Build status|
|
7 |
+
|
8 |
+
|Repology| |PyPI package| |Conda-forge| |Python Versions|
|
9 |
+
|
10 |
+
`Setuptools example <https://github.com/pybind/python_example>`_
|
11 |
+
• `Scikit-build example <https://github.com/pybind/scikit_build_example>`_
|
12 |
+
• `CMake example <https://github.com/pybind/cmake_example>`_
|
13 |
+
|
14 |
+
.. start
|
15 |
+
|
16 |
+
|
17 |
+
**pybind11** is a lightweight header-only library that exposes C++ types
|
18 |
+
in Python and vice versa, mainly to create Python bindings of existing
|
19 |
+
C++ code. Its goals and syntax are similar to the excellent
|
20 |
+
`Boost.Python <http://www.boost.org/doc/libs/1_58_0/libs/python/doc/>`_
|
21 |
+
library by David Abrahams: to minimize boilerplate code in traditional
|
22 |
+
extension modules by inferring type information using compile-time
|
23 |
+
introspection.
|
24 |
+
|
25 |
+
The main issue with Boost.Python—and the reason for creating such a
|
26 |
+
similar project—is Boost. Boost is an enormously large and complex suite
|
27 |
+
of utility libraries that works with almost every C++ compiler in
|
28 |
+
existence. This compatibility has its cost: arcane template tricks and
|
29 |
+
workarounds are necessary to support the oldest and buggiest of compiler
|
30 |
+
specimens. Now that C++11-compatible compilers are widely available,
|
31 |
+
this heavy machinery has become an excessively large and unnecessary
|
32 |
+
dependency.
|
33 |
+
|
34 |
+
Think of this library as a tiny self-contained version of Boost.Python
|
35 |
+
with everything stripped away that isn’t relevant for binding
|
36 |
+
generation. Without comments, the core header files only require ~4K
|
37 |
+
lines of code and depend on Python (2.7 or 3.5+, or PyPy) and the C++
|
38 |
+
standard library. This compact implementation was possible thanks to
|
39 |
+
some of the new C++11 language features (specifically: tuples, lambda
|
40 |
+
functions and variadic templates). Since its creation, this library has
|
41 |
+
grown beyond Boost.Python in many ways, leading to dramatically simpler
|
42 |
+
binding code in many common situations.
|
43 |
+
|
44 |
+
Tutorial and reference documentation is provided at
|
45 |
+
`pybind11.readthedocs.io <https://pybind11.readthedocs.io/en/latest>`_.
|
46 |
+
A PDF version of the manual is available
|
47 |
+
`here <https://pybind11.readthedocs.io/_/downloads/en/latest/pdf/>`_.
|
48 |
+
And the source code is always available at
|
49 |
+
`github.com/pybind/pybind11 <https://github.com/pybind/pybind11>`_.
|
50 |
+
|
51 |
+
|
52 |
+
Core features
|
53 |
+
-------------
|
54 |
+
|
55 |
+
|
56 |
+
pybind11 can map the following core C++ features to Python:
|
57 |
+
|
58 |
+
- Functions accepting and returning custom data structures per value,
|
59 |
+
reference, or pointer
|
60 |
+
- Instance methods and static methods
|
61 |
+
- Overloaded functions
|
62 |
+
- Instance attributes and static attributes
|
63 |
+
- Arbitrary exception types
|
64 |
+
- Enumerations
|
65 |
+
- Callbacks
|
66 |
+
- Iterators and ranges
|
67 |
+
- Custom operators
|
68 |
+
- Single and multiple inheritance
|
69 |
+
- STL data structures
|
70 |
+
- Smart pointers with reference counting like ``std::shared_ptr``
|
71 |
+
- Internal references with correct reference counting
|
72 |
+
- C++ classes with virtual (and pure virtual) methods can be extended
|
73 |
+
in Python
|
74 |
+
|
75 |
+
Goodies
|
76 |
+
-------
|
77 |
+
|
78 |
+
In addition to the core functionality, pybind11 provides some extra
|
79 |
+
goodies:
|
80 |
+
|
81 |
+
- Python 2.7, 3.5+, and PyPy/PyPy3 7.3 are supported with an
|
82 |
+
implementation-agnostic interface.
|
83 |
+
|
84 |
+
- It is possible to bind C++11 lambda functions with captured
|
85 |
+
variables. The lambda capture data is stored inside the resulting
|
86 |
+
Python function object.
|
87 |
+
|
88 |
+
- pybind11 uses C++11 move constructors and move assignment operators
|
89 |
+
whenever possible to efficiently transfer custom data types.
|
90 |
+
|
91 |
+
- It’s easy to expose the internal storage of custom data types through
|
92 |
+
Pythons’ buffer protocols. This is handy e.g. for fast conversion
|
93 |
+
between C++ matrix classes like Eigen and NumPy without expensive
|
94 |
+
copy operations.
|
95 |
+
|
96 |
+
- pybind11 can automatically vectorize functions so that they are
|
97 |
+
transparently applied to all entries of one or more NumPy array
|
98 |
+
arguments.
|
99 |
+
|
100 |
+
- Python's slice-based access and assignment operations can be
|
101 |
+
supported with just a few lines of code.
|
102 |
+
|
103 |
+
- Everything is contained in just a few header files; there is no need
|
104 |
+
to link against any additional libraries.
|
105 |
+
|
106 |
+
- Binaries are generally smaller by a factor of at least 2 compared to
|
107 |
+
equivalent bindings generated by Boost.Python. A recent pybind11
|
108 |
+
conversion of PyRosetta, an enormous Boost.Python binding project,
|
109 |
+
`reported <http://graylab.jhu.edu/RosettaCon2016/PyRosetta-4.pdf>`_
|
110 |
+
a binary size reduction of **5.4x** and compile time reduction by
|
111 |
+
**5.8x**.
|
112 |
+
|
113 |
+
- Function signatures are precomputed at compile time (using
|
114 |
+
``constexpr``), leading to smaller binaries.
|
115 |
+
|
116 |
+
- With little extra effort, C++ types can be pickled and unpickled
|
117 |
+
similar to regular Python objects.
|
118 |
+
|
119 |
+
Supported compilers
|
120 |
+
-------------------
|
121 |
+
|
122 |
+
1. Clang/LLVM 3.3 or newer (for Apple Xcode’s clang, this is 5.0.0 or
|
123 |
+
newer)
|
124 |
+
2. GCC 4.8 or newer
|
125 |
+
3. Microsoft Visual Studio 2015 Update 3 or newer
|
126 |
+
4. Intel classic C++ compiler 18 or newer (ICC 20.2 tested in CI)
|
127 |
+
5. Cygwin/GCC (previously tested on 2.5.1)
|
128 |
+
6. NVCC (CUDA 11.0 tested in CI)
|
129 |
+
7. NVIDIA PGI (20.9 tested in CI)
|
130 |
+
|
131 |
+
About
|
132 |
+
-----
|
133 |
+
|
134 |
+
This project was created by `Wenzel
|
135 |
+
Jakob <http://rgl.epfl.ch/people/wjakob>`_. Significant features and/or
|
136 |
+
improvements to the code were contributed by Jonas Adler, Lori A. Burns,
|
137 |
+
Sylvain Corlay, Eric Cousineau, Ralf Grosse-Kunstleve, Trent Houliston, Axel
|
138 |
+
Huebl, @hulucc, Yannick Jadoul, Sergey Lyskov Johan Mabille, Tomasz Miąsko,
|
139 |
+
Dean Moldovan, Ben Pritchard, Jason Rhinelander, Boris Schäling, Pim
|
140 |
+
Schellart, Henry Schreiner, Ivan Smirnov, Boris Staletic, and Patrick Stewart.
|
141 |
+
|
142 |
+
We thank Google for a generous financial contribution to the continuous
|
143 |
+
integration infrastructure used by this project.
|
144 |
+
|
145 |
+
|
146 |
+
Contributing
|
147 |
+
~~~~~~~~~~~~
|
148 |
+
|
149 |
+
See the `contributing
|
150 |
+
guide <https://github.com/pybind/pybind11/blob/master/.github/CONTRIBUTING.md>`_
|
151 |
+
for information on building and contributing to pybind11.
|
152 |
+
|
153 |
+
License
|
154 |
+
~~~~~~~
|
155 |
+
|
156 |
+
pybind11 is provided under a BSD-style license that can be found in the
|
157 |
+
`LICENSE <https://github.com/pybind/pybind11/blob/master/LICENSE>`_
|
158 |
+
file. By using, distributing, or contributing to this project, you agree
|
159 |
+
to the terms and conditions of this license.
|
160 |
+
|
161 |
+
.. |Latest Documentation Status| image:: https://readthedocs.org/projects/pybind11/badge?version=latest
|
162 |
+
:target: http://pybind11.readthedocs.org/en/latest
|
163 |
+
.. |Stable Documentation Status| image:: https://img.shields.io/badge/docs-stable-blue.svg
|
164 |
+
:target: http://pybind11.readthedocs.org/en/stable
|
165 |
+
.. |Gitter chat| image:: https://img.shields.io/gitter/room/gitterHQ/gitter.svg
|
166 |
+
:target: https://gitter.im/pybind/Lobby
|
167 |
+
.. |CI| image:: https://github.com/pybind/pybind11/workflows/CI/badge.svg
|
168 |
+
:target: https://github.com/pybind/pybind11/actions
|
169 |
+
.. |Build status| image:: https://ci.appveyor.com/api/projects/status/riaj54pn4h08xy40?svg=true
|
170 |
+
:target: https://ci.appveyor.com/project/wjakob/pybind11
|
171 |
+
.. |PyPI package| image:: https://img.shields.io/pypi/v/pybind11.svg
|
172 |
+
:target: https://pypi.org/project/pybind11/
|
173 |
+
.. |Conda-forge| image:: https://img.shields.io/conda/vn/conda-forge/pybind11.svg
|
174 |
+
:target: https://github.com/conda-forge/pybind11-feedstock
|
175 |
+
.. |Repology| image:: https://repology.org/badge/latest-versions/python:pybind11.svg
|
176 |
+
:target: https://repology.org/project/python:pybind11/versions
|
177 |
+
.. |Python Versions| image:: https://img.shields.io/pypi/pyversions/pybind11.svg
|
178 |
+
:target: https://pypi.org/project/pybind11/
|
third-party/DPVO/Pangolin/components/pango_python/pybind11/include/pybind11/detail/internals.h
ADDED
@@ -0,0 +1,365 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/*
|
2 |
+
pybind11/detail/internals.h: Internal data structure and related functions
|
3 |
+
|
4 |
+
Copyright (c) 2017 Wenzel Jakob <[email protected]>
|
5 |
+
|
6 |
+
All rights reserved. Use of this source code is governed by a
|
7 |
+
BSD-style license that can be found in the LICENSE file.
|
8 |
+
*/
|
9 |
+
|
10 |
+
#pragma once
|
11 |
+
|
12 |
+
#include "../pytypes.h"
|
13 |
+
|
14 |
+
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
|
15 |
+
PYBIND11_NAMESPACE_BEGIN(detail)
|
16 |
+
// Forward declarations
|
17 |
+
inline PyTypeObject *make_static_property_type();
|
18 |
+
inline PyTypeObject *make_default_metaclass();
|
19 |
+
inline PyObject *make_object_base_type(PyTypeObject *metaclass);
|
20 |
+
|
21 |
+
// The old Python Thread Local Storage (TLS) API is deprecated in Python 3.7 in favor of the new
|
22 |
+
// Thread Specific Storage (TSS) API.
|
23 |
+
#if PY_VERSION_HEX >= 0x03070000
|
24 |
+
# define PYBIND11_TLS_KEY_INIT(var) Py_tss_t *var = nullptr
|
25 |
+
# define PYBIND11_TLS_GET_VALUE(key) PyThread_tss_get((key))
|
26 |
+
# define PYBIND11_TLS_REPLACE_VALUE(key, value) PyThread_tss_set((key), (value))
|
27 |
+
# define PYBIND11_TLS_DELETE_VALUE(key) PyThread_tss_set((key), nullptr)
|
28 |
+
# define PYBIND11_TLS_FREE(key) PyThread_tss_free(key)
|
29 |
+
#else
|
30 |
+
// Usually an int but a long on Cygwin64 with Python 3.x
|
31 |
+
# define PYBIND11_TLS_KEY_INIT(var) decltype(PyThread_create_key()) var = 0
|
32 |
+
# define PYBIND11_TLS_GET_VALUE(key) PyThread_get_key_value((key))
|
33 |
+
# if PY_MAJOR_VERSION < 3
|
34 |
+
# define PYBIND11_TLS_DELETE_VALUE(key) \
|
35 |
+
PyThread_delete_key_value(key)
|
36 |
+
# define PYBIND11_TLS_REPLACE_VALUE(key, value) \
|
37 |
+
do { \
|
38 |
+
PyThread_delete_key_value((key)); \
|
39 |
+
PyThread_set_key_value((key), (value)); \
|
40 |
+
} while (false)
|
41 |
+
# else
|
42 |
+
# define PYBIND11_TLS_DELETE_VALUE(key) \
|
43 |
+
PyThread_set_key_value((key), nullptr)
|
44 |
+
# define PYBIND11_TLS_REPLACE_VALUE(key, value) \
|
45 |
+
PyThread_set_key_value((key), (value))
|
46 |
+
# endif
|
47 |
+
# define PYBIND11_TLS_FREE(key) (void)key
|
48 |
+
#endif
|
49 |
+
|
50 |
+
// Python loads modules by default with dlopen with the RTLD_LOCAL flag; under libc++ and possibly
|
51 |
+
// other STLs, this means `typeid(A)` from one module won't equal `typeid(A)` from another module
|
52 |
+
// even when `A` is the same, non-hidden-visibility type (e.g. from a common include). Under
|
53 |
+
// libstdc++, this doesn't happen: equality and the type_index hash are based on the type name,
|
54 |
+
// which works. If not under a known-good stl, provide our own name-based hash and equality
|
55 |
+
// functions that use the type name.
|
56 |
+
#if defined(__GLIBCXX__)
|
57 |
+
inline bool same_type(const std::type_info &lhs, const std::type_info &rhs) { return lhs == rhs; }
|
58 |
+
using type_hash = std::hash<std::type_index>;
|
59 |
+
using type_equal_to = std::equal_to<std::type_index>;
|
60 |
+
#else
|
61 |
+
inline bool same_type(const std::type_info &lhs, const std::type_info &rhs) {
|
62 |
+
return lhs.name() == rhs.name() || std::strcmp(lhs.name(), rhs.name()) == 0;
|
63 |
+
}
|
64 |
+
|
65 |
+
struct type_hash {
|
66 |
+
size_t operator()(const std::type_index &t) const {
|
67 |
+
size_t hash = 5381;
|
68 |
+
const char *ptr = t.name();
|
69 |
+
while (auto c = static_cast<unsigned char>(*ptr++))
|
70 |
+
hash = (hash * 33) ^ c;
|
71 |
+
return hash;
|
72 |
+
}
|
73 |
+
};
|
74 |
+
|
75 |
+
struct type_equal_to {
|
76 |
+
bool operator()(const std::type_index &lhs, const std::type_index &rhs) const {
|
77 |
+
return lhs.name() == rhs.name() || std::strcmp(lhs.name(), rhs.name()) == 0;
|
78 |
+
}
|
79 |
+
};
|
80 |
+
#endif
|
81 |
+
|
82 |
+
template <typename value_type>
|
83 |
+
using type_map = std::unordered_map<std::type_index, value_type, type_hash, type_equal_to>;
|
84 |
+
|
85 |
+
struct override_hash {
|
86 |
+
inline size_t operator()(const std::pair<const PyObject *, const char *>& v) const {
|
87 |
+
size_t value = std::hash<const void *>()(v.first);
|
88 |
+
value ^= std::hash<const void *>()(v.second) + 0x9e3779b9 + (value<<6) + (value>>2);
|
89 |
+
return value;
|
90 |
+
}
|
91 |
+
};
|
92 |
+
|
93 |
+
/// Internal data structure used to track registered instances and types.
|
94 |
+
/// Whenever binary incompatible changes are made to this structure,
|
95 |
+
/// `PYBIND11_INTERNALS_VERSION` must be incremented.
|
96 |
+
struct internals {
|
97 |
+
type_map<type_info *> registered_types_cpp; // std::type_index -> pybind11's type information
|
98 |
+
std::unordered_map<PyTypeObject *, std::vector<type_info *>> registered_types_py; // PyTypeObject* -> base type_info(s)
|
99 |
+
std::unordered_multimap<const void *, instance*> registered_instances; // void * -> instance*
|
100 |
+
std::unordered_set<std::pair<const PyObject *, const char *>, override_hash> inactive_override_cache;
|
101 |
+
type_map<std::vector<bool (*)(PyObject *, void *&)>> direct_conversions;
|
102 |
+
std::unordered_map<const PyObject *, std::vector<PyObject *>> patients;
|
103 |
+
std::forward_list<void (*) (std::exception_ptr)> registered_exception_translators;
|
104 |
+
std::unordered_map<std::string, void *> shared_data; // Custom data to be shared across extensions
|
105 |
+
std::vector<PyObject *> loader_patient_stack; // Used by `loader_life_support`
|
106 |
+
std::forward_list<std::string> static_strings; // Stores the std::strings backing detail::c_str()
|
107 |
+
PyTypeObject *static_property_type;
|
108 |
+
PyTypeObject *default_metaclass;
|
109 |
+
PyObject *instance_base;
|
110 |
+
#if defined(WITH_THREAD)
|
111 |
+
PYBIND11_TLS_KEY_INIT(tstate);
|
112 |
+
PyInterpreterState *istate = nullptr;
|
113 |
+
~internals() {
|
114 |
+
// This destructor is called *after* Py_Finalize() in finalize_interpreter().
|
115 |
+
// That *SHOULD BE* fine. The following details what happens when PyThread_tss_free is called.
|
116 |
+
// PYBIND11_TLS_FREE is PyThread_tss_free on python 3.7+. On older python, it does nothing.
|
117 |
+
// PyThread_tss_free calls PyThread_tss_delete and PyMem_RawFree.
|
118 |
+
// PyThread_tss_delete just calls TlsFree (on Windows) or pthread_key_delete (on *NIX). Neither
|
119 |
+
// of those have anything to do with CPython internals.
|
120 |
+
// PyMem_RawFree *requires* that the `tstate` be allocated with the CPython allocator.
|
121 |
+
PYBIND11_TLS_FREE(tstate);
|
122 |
+
}
|
123 |
+
#endif
|
124 |
+
};
|
125 |
+
|
126 |
+
/// Additional type information which does not fit into the PyTypeObject.
|
127 |
+
/// Changes to this struct also require bumping `PYBIND11_INTERNALS_VERSION`.
|
128 |
+
struct type_info {
|
129 |
+
PyTypeObject *type;
|
130 |
+
const std::type_info *cpptype;
|
131 |
+
size_t type_size, type_align, holder_size_in_ptrs;
|
132 |
+
void *(*operator_new)(size_t);
|
133 |
+
void (*init_instance)(instance *, const void *);
|
134 |
+
void (*dealloc)(value_and_holder &v_h);
|
135 |
+
std::vector<PyObject *(*)(PyObject *, PyTypeObject *)> implicit_conversions;
|
136 |
+
std::vector<std::pair<const std::type_info *, void *(*)(void *)>> implicit_casts;
|
137 |
+
std::vector<bool (*)(PyObject *, void *&)> *direct_conversions;
|
138 |
+
buffer_info *(*get_buffer)(PyObject *, void *) = nullptr;
|
139 |
+
void *get_buffer_data = nullptr;
|
140 |
+
void *(*module_local_load)(PyObject *, const type_info *) = nullptr;
|
141 |
+
/* A simple type never occurs as a (direct or indirect) parent
|
142 |
+
* of a class that makes use of multiple inheritance */
|
143 |
+
bool simple_type : 1;
|
144 |
+
/* True if there is no multiple inheritance in this type's inheritance tree */
|
145 |
+
bool simple_ancestors : 1;
|
146 |
+
/* for base vs derived holder_type checks */
|
147 |
+
bool default_holder : 1;
|
148 |
+
/* true if this is a type registered with py::module_local */
|
149 |
+
bool module_local : 1;
|
150 |
+
};
|
151 |
+
|
152 |
+
/// Tracks the `internals` and `type_info` ABI version independent of the main library version
|
153 |
+
#define PYBIND11_INTERNALS_VERSION 4
|
154 |
+
|
155 |
+
/// On MSVC, debug and release builds are not ABI-compatible!
|
156 |
+
#if defined(_MSC_VER) && defined(_DEBUG)
|
157 |
+
# define PYBIND11_BUILD_TYPE "_debug"
|
158 |
+
#else
|
159 |
+
# define PYBIND11_BUILD_TYPE ""
|
160 |
+
#endif
|
161 |
+
|
162 |
+
/// Let's assume that different compilers are ABI-incompatible.
|
163 |
+
/// A user can manually set this string if they know their
|
164 |
+
/// compiler is compatible.
|
165 |
+
#ifndef PYBIND11_COMPILER_TYPE
|
166 |
+
# if defined(_MSC_VER)
|
167 |
+
# define PYBIND11_COMPILER_TYPE "_msvc"
|
168 |
+
# elif defined(__INTEL_COMPILER)
|
169 |
+
# define PYBIND11_COMPILER_TYPE "_icc"
|
170 |
+
# elif defined(__clang__)
|
171 |
+
# define PYBIND11_COMPILER_TYPE "_clang"
|
172 |
+
# elif defined(__PGI)
|
173 |
+
# define PYBIND11_COMPILER_TYPE "_pgi"
|
174 |
+
# elif defined(__MINGW32__)
|
175 |
+
# define PYBIND11_COMPILER_TYPE "_mingw"
|
176 |
+
# elif defined(__CYGWIN__)
|
177 |
+
# define PYBIND11_COMPILER_TYPE "_gcc_cygwin"
|
178 |
+
# elif defined(__GNUC__)
|
179 |
+
# define PYBIND11_COMPILER_TYPE "_gcc"
|
180 |
+
# else
|
181 |
+
# define PYBIND11_COMPILER_TYPE "_unknown"
|
182 |
+
# endif
|
183 |
+
#endif
|
184 |
+
|
185 |
+
/// Also standard libs
|
186 |
+
#ifndef PYBIND11_STDLIB
|
187 |
+
# if defined(_LIBCPP_VERSION)
|
188 |
+
# define PYBIND11_STDLIB "_libcpp"
|
189 |
+
# elif defined(__GLIBCXX__) || defined(__GLIBCPP__)
|
190 |
+
# define PYBIND11_STDLIB "_libstdcpp"
|
191 |
+
# else
|
192 |
+
# define PYBIND11_STDLIB ""
|
193 |
+
# endif
|
194 |
+
#endif
|
195 |
+
|
196 |
+
/// On Linux/OSX, changes in __GXX_ABI_VERSION__ indicate ABI incompatibility.
|
197 |
+
#ifndef PYBIND11_BUILD_ABI
|
198 |
+
# if defined(__GXX_ABI_VERSION)
|
199 |
+
# define PYBIND11_BUILD_ABI "_cxxabi" PYBIND11_TOSTRING(__GXX_ABI_VERSION)
|
200 |
+
# else
|
201 |
+
# define PYBIND11_BUILD_ABI ""
|
202 |
+
# endif
|
203 |
+
#endif
|
204 |
+
|
205 |
+
#ifndef PYBIND11_INTERNALS_KIND
|
206 |
+
# if defined(WITH_THREAD)
|
207 |
+
# define PYBIND11_INTERNALS_KIND ""
|
208 |
+
# else
|
209 |
+
# define PYBIND11_INTERNALS_KIND "_without_thread"
|
210 |
+
# endif
|
211 |
+
#endif
|
212 |
+
|
213 |
+
#define PYBIND11_INTERNALS_ID "__pybind11_internals_v" \
|
214 |
+
PYBIND11_TOSTRING(PYBIND11_INTERNALS_VERSION) PYBIND11_INTERNALS_KIND PYBIND11_COMPILER_TYPE PYBIND11_STDLIB PYBIND11_BUILD_ABI PYBIND11_BUILD_TYPE "__"
|
215 |
+
|
216 |
+
#define PYBIND11_MODULE_LOCAL_ID "__pybind11_module_local_v" \
|
217 |
+
PYBIND11_TOSTRING(PYBIND11_INTERNALS_VERSION) PYBIND11_INTERNALS_KIND PYBIND11_COMPILER_TYPE PYBIND11_STDLIB PYBIND11_BUILD_ABI PYBIND11_BUILD_TYPE "__"
|
218 |
+
|
219 |
+
/// Each module locally stores a pointer to the `internals` data. The data
|
220 |
+
/// itself is shared among modules with the same `PYBIND11_INTERNALS_ID`.
|
221 |
+
inline internals **&get_internals_pp() {
|
222 |
+
static internals **internals_pp = nullptr;
|
223 |
+
return internals_pp;
|
224 |
+
}
|
225 |
+
|
226 |
+
inline void translate_exception(std::exception_ptr p) {
|
227 |
+
try {
|
228 |
+
if (p) std::rethrow_exception(p);
|
229 |
+
} catch (error_already_set &e) { e.restore(); return;
|
230 |
+
} catch (const builtin_exception &e) { e.set_error(); return;
|
231 |
+
} catch (const std::bad_alloc &e) { PyErr_SetString(PyExc_MemoryError, e.what()); return;
|
232 |
+
} catch (const std::domain_error &e) { PyErr_SetString(PyExc_ValueError, e.what()); return;
|
233 |
+
} catch (const std::invalid_argument &e) { PyErr_SetString(PyExc_ValueError, e.what()); return;
|
234 |
+
} catch (const std::length_error &e) { PyErr_SetString(PyExc_ValueError, e.what()); return;
|
235 |
+
} catch (const std::out_of_range &e) { PyErr_SetString(PyExc_IndexError, e.what()); return;
|
236 |
+
} catch (const std::range_error &e) { PyErr_SetString(PyExc_ValueError, e.what()); return;
|
237 |
+
} catch (const std::overflow_error &e) { PyErr_SetString(PyExc_OverflowError, e.what()); return;
|
238 |
+
} catch (const std::exception &e) { PyErr_SetString(PyExc_RuntimeError, e.what()); return;
|
239 |
+
} catch (...) {
|
240 |
+
PyErr_SetString(PyExc_RuntimeError, "Caught an unknown exception!");
|
241 |
+
return;
|
242 |
+
}
|
243 |
+
}
|
244 |
+
|
245 |
+
#if !defined(__GLIBCXX__)
|
246 |
+
inline void translate_local_exception(std::exception_ptr p) {
|
247 |
+
try {
|
248 |
+
if (p) std::rethrow_exception(p);
|
249 |
+
} catch (error_already_set &e) { e.restore(); return;
|
250 |
+
} catch (const builtin_exception &e) { e.set_error(); return;
|
251 |
+
}
|
252 |
+
}
|
253 |
+
#endif
|
254 |
+
|
255 |
+
/// Return a reference to the current `internals` data
|
256 |
+
PYBIND11_NOINLINE inline internals &get_internals() {
|
257 |
+
auto **&internals_pp = get_internals_pp();
|
258 |
+
if (internals_pp && *internals_pp)
|
259 |
+
return **internals_pp;
|
260 |
+
|
261 |
+
// Ensure that the GIL is held since we will need to make Python calls.
|
262 |
+
// Cannot use py::gil_scoped_acquire here since that constructor calls get_internals.
|
263 |
+
struct gil_scoped_acquire_local {
|
264 |
+
gil_scoped_acquire_local() : state (PyGILState_Ensure()) {}
|
265 |
+
~gil_scoped_acquire_local() { PyGILState_Release(state); }
|
266 |
+
const PyGILState_STATE state;
|
267 |
+
} gil;
|
268 |
+
|
269 |
+
PYBIND11_STR_TYPE id(PYBIND11_INTERNALS_ID);
|
270 |
+
auto builtins = handle(PyEval_GetBuiltins());
|
271 |
+
if (builtins.contains(id) && isinstance<capsule>(builtins[id])) {
|
272 |
+
internals_pp = static_cast<internals **>(capsule(builtins[id]));
|
273 |
+
|
274 |
+
// We loaded builtins through python's builtins, which means that our `error_already_set`
|
275 |
+
// and `builtin_exception` may be different local classes than the ones set up in the
|
276 |
+
// initial exception translator, below, so add another for our local exception classes.
|
277 |
+
//
|
278 |
+
// libstdc++ doesn't require this (types there are identified only by name)
|
279 |
+
// libc++ with CPython doesn't require this (types are explicitly exported)
|
280 |
+
// libc++ with PyPy still need it, awaiting further investigation
|
281 |
+
#if !defined(__GLIBCXX__)
|
282 |
+
(*internals_pp)->registered_exception_translators.push_front(&translate_local_exception);
|
283 |
+
#endif
|
284 |
+
} else {
|
285 |
+
if (!internals_pp) internals_pp = new internals*();
|
286 |
+
auto *&internals_ptr = *internals_pp;
|
287 |
+
internals_ptr = new internals();
|
288 |
+
#if defined(WITH_THREAD)
|
289 |
+
|
290 |
+
#if PY_VERSION_HEX < 0x03090000
|
291 |
+
PyEval_InitThreads();
|
292 |
+
#endif
|
293 |
+
PyThreadState *tstate = PyThreadState_Get();
|
294 |
+
#if PY_VERSION_HEX >= 0x03070000
|
295 |
+
internals_ptr->tstate = PyThread_tss_alloc();
|
296 |
+
if (!internals_ptr->tstate || (PyThread_tss_create(internals_ptr->tstate) != 0))
|
297 |
+
pybind11_fail("get_internals: could not successfully initialize the TSS key!");
|
298 |
+
PyThread_tss_set(internals_ptr->tstate, tstate);
|
299 |
+
#else
|
300 |
+
internals_ptr->tstate = PyThread_create_key();
|
301 |
+
if (internals_ptr->tstate == -1)
|
302 |
+
pybind11_fail("get_internals: could not successfully initialize the TLS key!");
|
303 |
+
PyThread_set_key_value(internals_ptr->tstate, tstate);
|
304 |
+
#endif
|
305 |
+
internals_ptr->istate = tstate->interp;
|
306 |
+
#endif
|
307 |
+
builtins[id] = capsule(internals_pp);
|
308 |
+
internals_ptr->registered_exception_translators.push_front(&translate_exception);
|
309 |
+
internals_ptr->static_property_type = make_static_property_type();
|
310 |
+
internals_ptr->default_metaclass = make_default_metaclass();
|
311 |
+
internals_ptr->instance_base = make_object_base_type(internals_ptr->default_metaclass);
|
312 |
+
}
|
313 |
+
return **internals_pp;
|
314 |
+
}
|
315 |
+
|
316 |
+
/// Works like `internals.registered_types_cpp`, but for module-local registered types:
|
317 |
+
inline type_map<type_info *> ®istered_local_types_cpp() {
|
318 |
+
static type_map<type_info *> locals{};
|
319 |
+
return locals;
|
320 |
+
}
|
321 |
+
|
322 |
+
/// Constructs a std::string with the given arguments, stores it in `internals`, and returns its
|
323 |
+
/// `c_str()`. Such strings objects have a long storage duration -- the internal strings are only
|
324 |
+
/// cleared when the program exits or after interpreter shutdown (when embedding), and so are
|
325 |
+
/// suitable for c-style strings needed by Python internals (such as PyTypeObject's tp_name).
|
326 |
+
template <typename... Args>
|
327 |
+
const char *c_str(Args &&...args) {
|
328 |
+
auto &strings = get_internals().static_strings;
|
329 |
+
strings.emplace_front(std::forward<Args>(args)...);
|
330 |
+
return strings.front().c_str();
|
331 |
+
}
|
332 |
+
|
333 |
+
PYBIND11_NAMESPACE_END(detail)
|
334 |
+
|
335 |
+
/// Returns a named pointer that is shared among all extension modules (using the same
|
336 |
+
/// pybind11 version) running in the current interpreter. Names starting with underscores
|
337 |
+
/// are reserved for internal usage. Returns `nullptr` if no matching entry was found.
|
338 |
+
inline PYBIND11_NOINLINE void *get_shared_data(const std::string &name) {
|
339 |
+
auto &internals = detail::get_internals();
|
340 |
+
auto it = internals.shared_data.find(name);
|
341 |
+
return it != internals.shared_data.end() ? it->second : nullptr;
|
342 |
+
}
|
343 |
+
|
344 |
+
/// Set the shared data that can be later recovered by `get_shared_data()`.
|
345 |
+
inline PYBIND11_NOINLINE void *set_shared_data(const std::string &name, void *data) {
|
346 |
+
detail::get_internals().shared_data[name] = data;
|
347 |
+
return data;
|
348 |
+
}
|
349 |
+
|
350 |
+
/// Returns a typed reference to a shared data entry (by using `get_shared_data()`) if
|
351 |
+
/// such entry exists. Otherwise, a new object of default-constructible type `T` is
|
352 |
+
/// added to the shared data under the given name and a reference to it is returned.
|
353 |
+
template<typename T>
|
354 |
+
T &get_or_create_shared_data(const std::string &name) {
|
355 |
+
auto &internals = detail::get_internals();
|
356 |
+
auto it = internals.shared_data.find(name);
|
357 |
+
T *ptr = (T *) (it != internals.shared_data.end() ? it->second : nullptr);
|
358 |
+
if (!ptr) {
|
359 |
+
ptr = new T();
|
360 |
+
internals.shared_data[name] = ptr;
|
361 |
+
}
|
362 |
+
return *ptr;
|
363 |
+
}
|
364 |
+
|
365 |
+
PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)
|
third-party/DPVO/Pangolin/components/pango_python/pybind11/include/pybind11/detail/type_caster_base.h
ADDED
@@ -0,0 +1,950 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/*
|
2 |
+
pybind11/detail/type_caster_base.h (originally first part of pybind11/cast.h)
|
3 |
+
|
4 |
+
Copyright (c) 2016 Wenzel Jakob <[email protected]>
|
5 |
+
|
6 |
+
All rights reserved. Use of this source code is governed by a
|
7 |
+
BSD-style license that can be found in the LICENSE file.
|
8 |
+
*/
|
9 |
+
|
10 |
+
#pragma once
|
11 |
+
|
12 |
+
#include "../pytypes.h"
|
13 |
+
#include "common.h"
|
14 |
+
#include "descr.h"
|
15 |
+
#include "internals.h"
|
16 |
+
#include "typeid.h"
|
17 |
+
#include <cstdint>
|
18 |
+
#include <iterator>
|
19 |
+
#include <new>
|
20 |
+
#include <string>
|
21 |
+
#include <type_traits>
|
22 |
+
#include <typeindex>
|
23 |
+
#include <typeinfo>
|
24 |
+
#include <unordered_map>
|
25 |
+
#include <utility>
|
26 |
+
#include <vector>
|
27 |
+
|
28 |
+
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
|
29 |
+
PYBIND11_NAMESPACE_BEGIN(detail)
|
30 |
+
|
31 |
+
/// A life support system for temporary objects created by `type_caster::load()`.
|
32 |
+
/// Adding a patient will keep it alive up until the enclosing function returns.
|
33 |
+
class loader_life_support {
|
34 |
+
public:
|
35 |
+
/// A new patient frame is created when a function is entered
|
36 |
+
loader_life_support() {
|
37 |
+
get_internals().loader_patient_stack.push_back(nullptr);
|
38 |
+
}
|
39 |
+
|
40 |
+
/// ... and destroyed after it returns
|
41 |
+
~loader_life_support() {
|
42 |
+
auto &stack = get_internals().loader_patient_stack;
|
43 |
+
if (stack.empty())
|
44 |
+
pybind11_fail("loader_life_support: internal error");
|
45 |
+
|
46 |
+
auto ptr = stack.back();
|
47 |
+
stack.pop_back();
|
48 |
+
Py_CLEAR(ptr);
|
49 |
+
|
50 |
+
// A heuristic to reduce the stack's capacity (e.g. after long recursive calls)
|
51 |
+
if (stack.capacity() > 16 && !stack.empty() && stack.capacity() / stack.size() > 2)
|
52 |
+
stack.shrink_to_fit();
|
53 |
+
}
|
54 |
+
|
55 |
+
/// This can only be used inside a pybind11-bound function, either by `argument_loader`
|
56 |
+
/// at argument preparation time or by `py::cast()` at execution time.
|
57 |
+
PYBIND11_NOINLINE static void add_patient(handle h) {
|
58 |
+
auto &stack = get_internals().loader_patient_stack;
|
59 |
+
if (stack.empty())
|
60 |
+
throw cast_error("When called outside a bound function, py::cast() cannot "
|
61 |
+
"do Python -> C++ conversions which require the creation "
|
62 |
+
"of temporary values");
|
63 |
+
|
64 |
+
auto &list_ptr = stack.back();
|
65 |
+
if (list_ptr == nullptr) {
|
66 |
+
list_ptr = PyList_New(1);
|
67 |
+
if (!list_ptr)
|
68 |
+
pybind11_fail("loader_life_support: error allocating list");
|
69 |
+
PyList_SET_ITEM(list_ptr, 0, h.inc_ref().ptr());
|
70 |
+
} else {
|
71 |
+
auto result = PyList_Append(list_ptr, h.ptr());
|
72 |
+
if (result == -1)
|
73 |
+
pybind11_fail("loader_life_support: error adding patient");
|
74 |
+
}
|
75 |
+
}
|
76 |
+
};
|
77 |
+
|
78 |
+
// Gets the cache entry for the given type, creating it if necessary. The return value is the pair
|
79 |
+
// returned by emplace, i.e. an iterator for the entry and a bool set to `true` if the entry was
|
80 |
+
// just created.
|
81 |
+
inline std::pair<decltype(internals::registered_types_py)::iterator, bool> all_type_info_get_cache(PyTypeObject *type);
|
82 |
+
|
83 |
+
// Populates a just-created cache entry.
|
84 |
+
PYBIND11_NOINLINE inline void all_type_info_populate(PyTypeObject *t, std::vector<type_info *> &bases) {
|
85 |
+
std::vector<PyTypeObject *> check;
|
86 |
+
for (handle parent : reinterpret_borrow<tuple>(t->tp_bases))
|
87 |
+
check.push_back((PyTypeObject *) parent.ptr());
|
88 |
+
|
89 |
+
auto const &type_dict = get_internals().registered_types_py;
|
90 |
+
for (size_t i = 0; i < check.size(); i++) {
|
91 |
+
auto type = check[i];
|
92 |
+
// Ignore Python2 old-style class super type:
|
93 |
+
if (!PyType_Check((PyObject *) type)) continue;
|
94 |
+
|
95 |
+
// Check `type` in the current set of registered python types:
|
96 |
+
auto it = type_dict.find(type);
|
97 |
+
if (it != type_dict.end()) {
|
98 |
+
// We found a cache entry for it, so it's either pybind-registered or has pre-computed
|
99 |
+
// pybind bases, but we have to make sure we haven't already seen the type(s) before: we
|
100 |
+
// want to follow Python/virtual C++ rules that there should only be one instance of a
|
101 |
+
// common base.
|
102 |
+
for (auto *tinfo : it->second) {
|
103 |
+
// NB: Could use a second set here, rather than doing a linear search, but since
|
104 |
+
// having a large number of immediate pybind11-registered types seems fairly
|
105 |
+
// unlikely, that probably isn't worthwhile.
|
106 |
+
bool found = false;
|
107 |
+
for (auto *known : bases) {
|
108 |
+
if (known == tinfo) { found = true; break; }
|
109 |
+
}
|
110 |
+
if (!found) bases.push_back(tinfo);
|
111 |
+
}
|
112 |
+
}
|
113 |
+
else if (type->tp_bases) {
|
114 |
+
// It's some python type, so keep follow its bases classes to look for one or more
|
115 |
+
// registered types
|
116 |
+
if (i + 1 == check.size()) {
|
117 |
+
// When we're at the end, we can pop off the current element to avoid growing
|
118 |
+
// `check` when adding just one base (which is typical--i.e. when there is no
|
119 |
+
// multiple inheritance)
|
120 |
+
check.pop_back();
|
121 |
+
i--;
|
122 |
+
}
|
123 |
+
for (handle parent : reinterpret_borrow<tuple>(type->tp_bases))
|
124 |
+
check.push_back((PyTypeObject *) parent.ptr());
|
125 |
+
}
|
126 |
+
}
|
127 |
+
}
|
128 |
+
|
129 |
+
/**
|
130 |
+
* Extracts vector of type_info pointers of pybind-registered roots of the given Python type. Will
|
131 |
+
* be just 1 pybind type for the Python type of a pybind-registered class, or for any Python-side
|
132 |
+
* derived class that uses single inheritance. Will contain as many types as required for a Python
|
133 |
+
* class that uses multiple inheritance to inherit (directly or indirectly) from multiple
|
134 |
+
* pybind-registered classes. Will be empty if neither the type nor any base classes are
|
135 |
+
* pybind-registered.
|
136 |
+
*
|
137 |
+
* The value is cached for the lifetime of the Python type.
|
138 |
+
*/
|
139 |
+
inline const std::vector<detail::type_info *> &all_type_info(PyTypeObject *type) {
|
140 |
+
auto ins = all_type_info_get_cache(type);
|
141 |
+
if (ins.second)
|
142 |
+
// New cache entry: populate it
|
143 |
+
all_type_info_populate(type, ins.first->second);
|
144 |
+
|
145 |
+
return ins.first->second;
|
146 |
+
}
|
147 |
+
|
148 |
+
/**
|
149 |
+
* Gets a single pybind11 type info for a python type. Returns nullptr if neither the type nor any
|
150 |
+
* ancestors are pybind11-registered. Throws an exception if there are multiple bases--use
|
151 |
+
* `all_type_info` instead if you want to support multiple bases.
|
152 |
+
*/
|
153 |
+
PYBIND11_NOINLINE inline detail::type_info* get_type_info(PyTypeObject *type) {
|
154 |
+
auto &bases = all_type_info(type);
|
155 |
+
if (bases.empty())
|
156 |
+
return nullptr;
|
157 |
+
if (bases.size() > 1)
|
158 |
+
pybind11_fail("pybind11::detail::get_type_info: type has multiple pybind11-registered bases");
|
159 |
+
return bases.front();
|
160 |
+
}
|
161 |
+
|
162 |
+
inline detail::type_info *get_local_type_info(const std::type_index &tp) {
|
163 |
+
auto &locals = registered_local_types_cpp();
|
164 |
+
auto it = locals.find(tp);
|
165 |
+
if (it != locals.end())
|
166 |
+
return it->second;
|
167 |
+
return nullptr;
|
168 |
+
}
|
169 |
+
|
170 |
+
inline detail::type_info *get_global_type_info(const std::type_index &tp) {
|
171 |
+
auto &types = get_internals().registered_types_cpp;
|
172 |
+
auto it = types.find(tp);
|
173 |
+
if (it != types.end())
|
174 |
+
return it->second;
|
175 |
+
return nullptr;
|
176 |
+
}
|
177 |
+
|
178 |
+
/// Return the type info for a given C++ type; on lookup failure can either throw or return nullptr.
|
179 |
+
PYBIND11_NOINLINE inline detail::type_info *get_type_info(const std::type_index &tp,
|
180 |
+
bool throw_if_missing = false) {
|
181 |
+
if (auto ltype = get_local_type_info(tp))
|
182 |
+
return ltype;
|
183 |
+
if (auto gtype = get_global_type_info(tp))
|
184 |
+
return gtype;
|
185 |
+
|
186 |
+
if (throw_if_missing) {
|
187 |
+
std::string tname = tp.name();
|
188 |
+
detail::clean_type_id(tname);
|
189 |
+
pybind11_fail("pybind11::detail::get_type_info: unable to find type info for \"" + tname + "\"");
|
190 |
+
}
|
191 |
+
return nullptr;
|
192 |
+
}
|
193 |
+
|
194 |
+
PYBIND11_NOINLINE inline handle get_type_handle(const std::type_info &tp, bool throw_if_missing) {
|
195 |
+
detail::type_info *type_info = get_type_info(tp, throw_if_missing);
|
196 |
+
return handle(type_info ? ((PyObject *) type_info->type) : nullptr);
|
197 |
+
}
|
198 |
+
|
199 |
+
// Searches the inheritance graph for a registered Python instance, using all_type_info().
|
200 |
+
PYBIND11_NOINLINE inline handle find_registered_python_instance(void *src,
|
201 |
+
const detail::type_info *tinfo) {
|
202 |
+
auto it_instances = get_internals().registered_instances.equal_range(src);
|
203 |
+
for (auto it_i = it_instances.first; it_i != it_instances.second; ++it_i) {
|
204 |
+
for (auto instance_type : detail::all_type_info(Py_TYPE(it_i->second))) {
|
205 |
+
if (instance_type && same_type(*instance_type->cpptype, *tinfo->cpptype))
|
206 |
+
return handle((PyObject *) it_i->second).inc_ref();
|
207 |
+
}
|
208 |
+
}
|
209 |
+
return handle();
|
210 |
+
}
|
211 |
+
|
212 |
+
struct value_and_holder {
|
213 |
+
instance *inst = nullptr;
|
214 |
+
size_t index = 0u;
|
215 |
+
const detail::type_info *type = nullptr;
|
216 |
+
void **vh = nullptr;
|
217 |
+
|
218 |
+
// Main constructor for a found value/holder:
|
219 |
+
value_and_holder(instance *i, const detail::type_info *type, size_t vpos, size_t index) :
|
220 |
+
inst{i}, index{index}, type{type},
|
221 |
+
vh{inst->simple_layout ? inst->simple_value_holder : &inst->nonsimple.values_and_holders[vpos]}
|
222 |
+
{}
|
223 |
+
|
224 |
+
// Default constructor (used to signal a value-and-holder not found by get_value_and_holder())
|
225 |
+
value_and_holder() = default;
|
226 |
+
|
227 |
+
// Used for past-the-end iterator
|
228 |
+
value_and_holder(size_t index) : index{index} {}
|
229 |
+
|
230 |
+
template <typename V = void> V *&value_ptr() const {
|
231 |
+
return reinterpret_cast<V *&>(vh[0]);
|
232 |
+
}
|
233 |
+
// True if this `value_and_holder` has a non-null value pointer
|
234 |
+
explicit operator bool() const { return value_ptr() != nullptr; }
|
235 |
+
|
236 |
+
template <typename H> H &holder() const {
|
237 |
+
return reinterpret_cast<H &>(vh[1]);
|
238 |
+
}
|
239 |
+
bool holder_constructed() const {
|
240 |
+
return inst->simple_layout
|
241 |
+
? inst->simple_holder_constructed
|
242 |
+
: (inst->nonsimple.status[index] & instance::status_holder_constructed) != 0u;
|
243 |
+
}
|
244 |
+
void set_holder_constructed(bool v = true) const {
|
245 |
+
if (inst->simple_layout)
|
246 |
+
inst->simple_holder_constructed = v;
|
247 |
+
else if (v)
|
248 |
+
inst->nonsimple.status[index] |= instance::status_holder_constructed;
|
249 |
+
else
|
250 |
+
inst->nonsimple.status[index] &= (std::uint8_t) ~instance::status_holder_constructed;
|
251 |
+
}
|
252 |
+
bool instance_registered() const {
|
253 |
+
return inst->simple_layout
|
254 |
+
? inst->simple_instance_registered
|
255 |
+
: ((inst->nonsimple.status[index] & instance::status_instance_registered) != 0);
|
256 |
+
}
|
257 |
+
void set_instance_registered(bool v = true) const {
|
258 |
+
if (inst->simple_layout)
|
259 |
+
inst->simple_instance_registered = v;
|
260 |
+
else if (v)
|
261 |
+
inst->nonsimple.status[index] |= instance::status_instance_registered;
|
262 |
+
else
|
263 |
+
inst->nonsimple.status[index] &= (std::uint8_t) ~instance::status_instance_registered;
|
264 |
+
}
|
265 |
+
};
|
266 |
+
|
267 |
+
// Container for accessing and iterating over an instance's values/holders
|
268 |
+
struct values_and_holders {
|
269 |
+
private:
|
270 |
+
instance *inst;
|
271 |
+
using type_vec = std::vector<detail::type_info *>;
|
272 |
+
const type_vec &tinfo;
|
273 |
+
|
274 |
+
public:
|
275 |
+
values_and_holders(instance *inst) : inst{inst}, tinfo(all_type_info(Py_TYPE(inst))) {}
|
276 |
+
|
277 |
+
struct iterator {
|
278 |
+
private:
|
279 |
+
instance *inst = nullptr;
|
280 |
+
const type_vec *types = nullptr;
|
281 |
+
value_and_holder curr;
|
282 |
+
friend struct values_and_holders;
|
283 |
+
iterator(instance *inst, const type_vec *tinfo)
|
284 |
+
: inst{inst}, types{tinfo},
|
285 |
+
curr(inst /* instance */,
|
286 |
+
types->empty() ? nullptr : (*types)[0] /* type info */,
|
287 |
+
0, /* vpos: (non-simple types only): the first vptr comes first */
|
288 |
+
0 /* index */)
|
289 |
+
{}
|
290 |
+
// Past-the-end iterator:
|
291 |
+
iterator(size_t end) : curr(end) {}
|
292 |
+
public:
|
293 |
+
bool operator==(const iterator &other) const { return curr.index == other.curr.index; }
|
294 |
+
bool operator!=(const iterator &other) const { return curr.index != other.curr.index; }
|
295 |
+
iterator &operator++() {
|
296 |
+
if (!inst->simple_layout)
|
297 |
+
curr.vh += 1 + (*types)[curr.index]->holder_size_in_ptrs;
|
298 |
+
++curr.index;
|
299 |
+
curr.type = curr.index < types->size() ? (*types)[curr.index] : nullptr;
|
300 |
+
return *this;
|
301 |
+
}
|
302 |
+
value_and_holder &operator*() { return curr; }
|
303 |
+
value_and_holder *operator->() { return &curr; }
|
304 |
+
};
|
305 |
+
|
306 |
+
iterator begin() { return iterator(inst, &tinfo); }
|
307 |
+
iterator end() { return iterator(tinfo.size()); }
|
308 |
+
|
309 |
+
iterator find(const type_info *find_type) {
|
310 |
+
auto it = begin(), endit = end();
|
311 |
+
while (it != endit && it->type != find_type) ++it;
|
312 |
+
return it;
|
313 |
+
}
|
314 |
+
|
315 |
+
size_t size() { return tinfo.size(); }
|
316 |
+
};
|
317 |
+
|
318 |
+
/**
|
319 |
+
* Extracts C++ value and holder pointer references from an instance (which may contain multiple
|
320 |
+
* values/holders for python-side multiple inheritance) that match the given type. Throws an error
|
321 |
+
* if the given type (or ValueType, if omitted) is not a pybind11 base of the given instance. If
|
322 |
+
* `find_type` is omitted (or explicitly specified as nullptr) the first value/holder are returned,
|
323 |
+
* regardless of type (and the resulting .type will be nullptr).
|
324 |
+
*
|
325 |
+
* The returned object should be short-lived: in particular, it must not outlive the called-upon
|
326 |
+
* instance.
|
327 |
+
*/
|
328 |
+
PYBIND11_NOINLINE inline value_and_holder instance::get_value_and_holder(const type_info *find_type /*= nullptr default in common.h*/, bool throw_if_missing /*= true in common.h*/) {
|
329 |
+
// Optimize common case:
|
330 |
+
if (!find_type || Py_TYPE(this) == find_type->type)
|
331 |
+
return value_and_holder(this, find_type, 0, 0);
|
332 |
+
|
333 |
+
detail::values_and_holders vhs(this);
|
334 |
+
auto it = vhs.find(find_type);
|
335 |
+
if (it != vhs.end())
|
336 |
+
return *it;
|
337 |
+
|
338 |
+
if (!throw_if_missing)
|
339 |
+
return value_and_holder();
|
340 |
+
|
341 |
+
#if defined(NDEBUG)
|
342 |
+
pybind11_fail("pybind11::detail::instance::get_value_and_holder: "
|
343 |
+
"type is not a pybind11 base of the given instance "
|
344 |
+
"(compile in debug mode for type details)");
|
345 |
+
#else
|
346 |
+
pybind11_fail("pybind11::detail::instance::get_value_and_holder: `" +
|
347 |
+
get_fully_qualified_tp_name(find_type->type) + "' is not a pybind11 base of the given `" +
|
348 |
+
get_fully_qualified_tp_name(Py_TYPE(this)) + "' instance");
|
349 |
+
#endif
|
350 |
+
}
|
351 |
+
|
352 |
+
PYBIND11_NOINLINE inline void instance::allocate_layout() {
|
353 |
+
auto &tinfo = all_type_info(Py_TYPE(this));
|
354 |
+
|
355 |
+
const size_t n_types = tinfo.size();
|
356 |
+
|
357 |
+
if (n_types == 0)
|
358 |
+
pybind11_fail("instance allocation failed: new instance has no pybind11-registered base types");
|
359 |
+
|
360 |
+
simple_layout =
|
361 |
+
n_types == 1 && tinfo.front()->holder_size_in_ptrs <= instance_simple_holder_in_ptrs();
|
362 |
+
|
363 |
+
// Simple path: no python-side multiple inheritance, and a small-enough holder
|
364 |
+
if (simple_layout) {
|
365 |
+
simple_value_holder[0] = nullptr;
|
366 |
+
simple_holder_constructed = false;
|
367 |
+
simple_instance_registered = false;
|
368 |
+
}
|
369 |
+
else { // multiple base types or a too-large holder
|
370 |
+
// Allocate space to hold: [v1*][h1][v2*][h2]...[bb...] where [vN*] is a value pointer,
|
371 |
+
// [hN] is the (uninitialized) holder instance for value N, and [bb...] is a set of bool
|
372 |
+
// values that tracks whether each associated holder has been initialized. Each [block] is
|
373 |
+
// padded, if necessary, to an integer multiple of sizeof(void *).
|
374 |
+
size_t space = 0;
|
375 |
+
for (auto t : tinfo) {
|
376 |
+
space += 1; // value pointer
|
377 |
+
space += t->holder_size_in_ptrs; // holder instance
|
378 |
+
}
|
379 |
+
size_t flags_at = space;
|
380 |
+
space += size_in_ptrs(n_types); // status bytes (holder_constructed and instance_registered)
|
381 |
+
|
382 |
+
// Allocate space for flags, values, and holders, and initialize it to 0 (flags and values,
|
383 |
+
// in particular, need to be 0). Use Python's memory allocation functions: in Python 3.6
|
384 |
+
// they default to using pymalloc, which is designed to be efficient for small allocations
|
385 |
+
// like the one we're doing here; in earlier versions (and for larger allocations) they are
|
386 |
+
// just wrappers around malloc.
|
387 |
+
#if PY_VERSION_HEX >= 0x03050000
|
388 |
+
nonsimple.values_and_holders = (void **) PyMem_Calloc(space, sizeof(void *));
|
389 |
+
if (!nonsimple.values_and_holders) throw std::bad_alloc();
|
390 |
+
#else
|
391 |
+
nonsimple.values_and_holders = (void **) PyMem_New(void *, space);
|
392 |
+
if (!nonsimple.values_and_holders) throw std::bad_alloc();
|
393 |
+
std::memset(nonsimple.values_and_holders, 0, space * sizeof(void *));
|
394 |
+
#endif
|
395 |
+
nonsimple.status = reinterpret_cast<std::uint8_t *>(&nonsimple.values_and_holders[flags_at]);
|
396 |
+
}
|
397 |
+
owned = true;
|
398 |
+
}
|
399 |
+
|
400 |
+
PYBIND11_NOINLINE inline void instance::deallocate_layout() const {
|
401 |
+
if (!simple_layout)
|
402 |
+
PyMem_Free(nonsimple.values_and_holders);
|
403 |
+
}
|
404 |
+
|
405 |
+
PYBIND11_NOINLINE inline bool isinstance_generic(handle obj, const std::type_info &tp) {
|
406 |
+
handle type = detail::get_type_handle(tp, false);
|
407 |
+
if (!type)
|
408 |
+
return false;
|
409 |
+
return isinstance(obj, type);
|
410 |
+
}
|
411 |
+
|
412 |
+
PYBIND11_NOINLINE inline std::string error_string() {
|
413 |
+
if (!PyErr_Occurred()) {
|
414 |
+
PyErr_SetString(PyExc_RuntimeError, "Unknown internal error occurred");
|
415 |
+
return "Unknown internal error occurred";
|
416 |
+
}
|
417 |
+
|
418 |
+
error_scope scope; // Preserve error state
|
419 |
+
|
420 |
+
std::string errorString;
|
421 |
+
if (scope.type) {
|
422 |
+
errorString += handle(scope.type).attr("__name__").cast<std::string>();
|
423 |
+
errorString += ": ";
|
424 |
+
}
|
425 |
+
if (scope.value)
|
426 |
+
errorString += (std::string) str(scope.value);
|
427 |
+
|
428 |
+
PyErr_NormalizeException(&scope.type, &scope.value, &scope.trace);
|
429 |
+
|
430 |
+
#if PY_MAJOR_VERSION >= 3
|
431 |
+
if (scope.trace != nullptr)
|
432 |
+
PyException_SetTraceback(scope.value, scope.trace);
|
433 |
+
#endif
|
434 |
+
|
435 |
+
#if !defined(PYPY_VERSION)
|
436 |
+
if (scope.trace) {
|
437 |
+
auto *trace = (PyTracebackObject *) scope.trace;
|
438 |
+
|
439 |
+
/* Get the deepest trace possible */
|
440 |
+
while (trace->tb_next)
|
441 |
+
trace = trace->tb_next;
|
442 |
+
|
443 |
+
PyFrameObject *frame = trace->tb_frame;
|
444 |
+
errorString += "\n\nAt:\n";
|
445 |
+
while (frame) {
|
446 |
+
int lineno = PyFrame_GetLineNumber(frame);
|
447 |
+
errorString +=
|
448 |
+
" " + handle(frame->f_code->co_filename).cast<std::string>() +
|
449 |
+
"(" + std::to_string(lineno) + "): " +
|
450 |
+
handle(frame->f_code->co_name).cast<std::string>() + "\n";
|
451 |
+
frame = frame->f_back;
|
452 |
+
}
|
453 |
+
}
|
454 |
+
#endif
|
455 |
+
|
456 |
+
return errorString;
|
457 |
+
}
|
458 |
+
|
459 |
+
PYBIND11_NOINLINE inline handle get_object_handle(const void *ptr, const detail::type_info *type ) {
|
460 |
+
auto &instances = get_internals().registered_instances;
|
461 |
+
auto range = instances.equal_range(ptr);
|
462 |
+
for (auto it = range.first; it != range.second; ++it) {
|
463 |
+
for (const auto &vh : values_and_holders(it->second)) {
|
464 |
+
if (vh.type == type)
|
465 |
+
return handle((PyObject *) it->second);
|
466 |
+
}
|
467 |
+
}
|
468 |
+
return handle();
|
469 |
+
}
|
470 |
+
|
471 |
+
inline PyThreadState *get_thread_state_unchecked() {
|
472 |
+
#if defined(PYPY_VERSION)
|
473 |
+
return PyThreadState_GET();
|
474 |
+
#elif PY_VERSION_HEX < 0x03000000
|
475 |
+
return _PyThreadState_Current;
|
476 |
+
#elif PY_VERSION_HEX < 0x03050000
|
477 |
+
return (PyThreadState*) _Py_atomic_load_relaxed(&_PyThreadState_Current);
|
478 |
+
#elif PY_VERSION_HEX < 0x03050200
|
479 |
+
return (PyThreadState*) _PyThreadState_Current.value;
|
480 |
+
#else
|
481 |
+
return _PyThreadState_UncheckedGet();
|
482 |
+
#endif
|
483 |
+
}
|
484 |
+
|
485 |
+
// Forward declarations
|
486 |
+
inline void keep_alive_impl(handle nurse, handle patient);
|
487 |
+
inline PyObject *make_new_instance(PyTypeObject *type);
|
488 |
+
|
489 |
+
class type_caster_generic {
|
490 |
+
public:
|
491 |
+
PYBIND11_NOINLINE type_caster_generic(const std::type_info &type_info)
|
492 |
+
: typeinfo(get_type_info(type_info)), cpptype(&type_info) { }
|
493 |
+
|
494 |
+
type_caster_generic(const type_info *typeinfo)
|
495 |
+
: typeinfo(typeinfo), cpptype(typeinfo ? typeinfo->cpptype : nullptr) { }
|
496 |
+
|
497 |
+
bool load(handle src, bool convert) {
|
498 |
+
return load_impl<type_caster_generic>(src, convert);
|
499 |
+
}
|
500 |
+
|
501 |
+
PYBIND11_NOINLINE static handle cast(const void *_src, return_value_policy policy, handle parent,
|
502 |
+
const detail::type_info *tinfo,
|
503 |
+
void *(*copy_constructor)(const void *),
|
504 |
+
void *(*move_constructor)(const void *),
|
505 |
+
const void *existing_holder = nullptr) {
|
506 |
+
if (!tinfo) // no type info: error will be set already
|
507 |
+
return handle();
|
508 |
+
|
509 |
+
void *src = const_cast<void *>(_src);
|
510 |
+
if (src == nullptr)
|
511 |
+
return none().release();
|
512 |
+
|
513 |
+
if (handle registered_inst = find_registered_python_instance(src, tinfo))
|
514 |
+
return registered_inst;
|
515 |
+
|
516 |
+
auto inst = reinterpret_steal<object>(make_new_instance(tinfo->type));
|
517 |
+
auto wrapper = reinterpret_cast<instance *>(inst.ptr());
|
518 |
+
wrapper->owned = false;
|
519 |
+
void *&valueptr = values_and_holders(wrapper).begin()->value_ptr();
|
520 |
+
|
521 |
+
switch (policy) {
|
522 |
+
case return_value_policy::automatic:
|
523 |
+
case return_value_policy::take_ownership:
|
524 |
+
valueptr = src;
|
525 |
+
wrapper->owned = true;
|
526 |
+
break;
|
527 |
+
|
528 |
+
case return_value_policy::automatic_reference:
|
529 |
+
case return_value_policy::reference:
|
530 |
+
valueptr = src;
|
531 |
+
wrapper->owned = false;
|
532 |
+
break;
|
533 |
+
|
534 |
+
case return_value_policy::copy:
|
535 |
+
if (copy_constructor)
|
536 |
+
valueptr = copy_constructor(src);
|
537 |
+
else {
|
538 |
+
#if defined(NDEBUG)
|
539 |
+
throw cast_error("return_value_policy = copy, but type is "
|
540 |
+
"non-copyable! (compile in debug mode for details)");
|
541 |
+
#else
|
542 |
+
std::string type_name(tinfo->cpptype->name());
|
543 |
+
detail::clean_type_id(type_name);
|
544 |
+
throw cast_error("return_value_policy = copy, but type " +
|
545 |
+
type_name + " is non-copyable!");
|
546 |
+
#endif
|
547 |
+
}
|
548 |
+
wrapper->owned = true;
|
549 |
+
break;
|
550 |
+
|
551 |
+
case return_value_policy::move:
|
552 |
+
if (move_constructor)
|
553 |
+
valueptr = move_constructor(src);
|
554 |
+
else if (copy_constructor)
|
555 |
+
valueptr = copy_constructor(src);
|
556 |
+
else {
|
557 |
+
#if defined(NDEBUG)
|
558 |
+
throw cast_error("return_value_policy = move, but type is neither "
|
559 |
+
"movable nor copyable! "
|
560 |
+
"(compile in debug mode for details)");
|
561 |
+
#else
|
562 |
+
std::string type_name(tinfo->cpptype->name());
|
563 |
+
detail::clean_type_id(type_name);
|
564 |
+
throw cast_error("return_value_policy = move, but type " +
|
565 |
+
type_name + " is neither movable nor copyable!");
|
566 |
+
#endif
|
567 |
+
}
|
568 |
+
wrapper->owned = true;
|
569 |
+
break;
|
570 |
+
|
571 |
+
case return_value_policy::reference_internal:
|
572 |
+
valueptr = src;
|
573 |
+
wrapper->owned = false;
|
574 |
+
keep_alive_impl(inst, parent);
|
575 |
+
break;
|
576 |
+
|
577 |
+
default:
|
578 |
+
throw cast_error("unhandled return_value_policy: should not happen!");
|
579 |
+
}
|
580 |
+
|
581 |
+
tinfo->init_instance(wrapper, existing_holder);
|
582 |
+
|
583 |
+
return inst.release();
|
584 |
+
}
|
585 |
+
|
586 |
+
// Base methods for generic caster; there are overridden in copyable_holder_caster
|
587 |
+
void load_value(value_and_holder &&v_h) {
|
588 |
+
auto *&vptr = v_h.value_ptr();
|
589 |
+
// Lazy allocation for unallocated values:
|
590 |
+
if (vptr == nullptr) {
|
591 |
+
auto *type = v_h.type ? v_h.type : typeinfo;
|
592 |
+
if (type->operator_new) {
|
593 |
+
vptr = type->operator_new(type->type_size);
|
594 |
+
} else {
|
595 |
+
#if defined(__cpp_aligned_new) && (!defined(_MSC_VER) || _MSC_VER >= 1912)
|
596 |
+
if (type->type_align > __STDCPP_DEFAULT_NEW_ALIGNMENT__)
|
597 |
+
vptr = ::operator new(type->type_size,
|
598 |
+
std::align_val_t(type->type_align));
|
599 |
+
else
|
600 |
+
#endif
|
601 |
+
vptr = ::operator new(type->type_size);
|
602 |
+
}
|
603 |
+
}
|
604 |
+
value = vptr;
|
605 |
+
}
|
606 |
+
bool try_implicit_casts(handle src, bool convert) {
|
607 |
+
for (auto &cast : typeinfo->implicit_casts) {
|
608 |
+
type_caster_generic sub_caster(*cast.first);
|
609 |
+
if (sub_caster.load(src, convert)) {
|
610 |
+
value = cast.second(sub_caster.value);
|
611 |
+
return true;
|
612 |
+
}
|
613 |
+
}
|
614 |
+
return false;
|
615 |
+
}
|
616 |
+
bool try_direct_conversions(handle src) {
|
617 |
+
for (auto &converter : *typeinfo->direct_conversions) {
|
618 |
+
if (converter(src.ptr(), value))
|
619 |
+
return true;
|
620 |
+
}
|
621 |
+
return false;
|
622 |
+
}
|
623 |
+
void check_holder_compat() {}
|
624 |
+
|
625 |
+
PYBIND11_NOINLINE static void *local_load(PyObject *src, const type_info *ti) {
|
626 |
+
auto caster = type_caster_generic(ti);
|
627 |
+
if (caster.load(src, false))
|
628 |
+
return caster.value;
|
629 |
+
return nullptr;
|
630 |
+
}
|
631 |
+
|
632 |
+
/// Try to load with foreign typeinfo, if available. Used when there is no
|
633 |
+
/// native typeinfo, or when the native one wasn't able to produce a value.
|
634 |
+
PYBIND11_NOINLINE bool try_load_foreign_module_local(handle src) {
|
635 |
+
constexpr auto *local_key = PYBIND11_MODULE_LOCAL_ID;
|
636 |
+
const auto pytype = type::handle_of(src);
|
637 |
+
if (!hasattr(pytype, local_key))
|
638 |
+
return false;
|
639 |
+
|
640 |
+
type_info *foreign_typeinfo = reinterpret_borrow<capsule>(getattr(pytype, local_key));
|
641 |
+
// Only consider this foreign loader if actually foreign and is a loader of the correct cpp type
|
642 |
+
if (foreign_typeinfo->module_local_load == &local_load
|
643 |
+
|| (cpptype && !same_type(*cpptype, *foreign_typeinfo->cpptype)))
|
644 |
+
return false;
|
645 |
+
|
646 |
+
if (auto result = foreign_typeinfo->module_local_load(src.ptr(), foreign_typeinfo)) {
|
647 |
+
value = result;
|
648 |
+
return true;
|
649 |
+
}
|
650 |
+
return false;
|
651 |
+
}
|
652 |
+
|
653 |
+
// Implementation of `load`; this takes the type of `this` so that it can dispatch the relevant
|
654 |
+
// bits of code between here and copyable_holder_caster where the two classes need different
|
655 |
+
// logic (without having to resort to virtual inheritance).
|
656 |
+
template <typename ThisT>
|
657 |
+
PYBIND11_NOINLINE bool load_impl(handle src, bool convert) {
|
658 |
+
if (!src) return false;
|
659 |
+
if (!typeinfo) return try_load_foreign_module_local(src);
|
660 |
+
|
661 |
+
auto &this_ = static_cast<ThisT &>(*this);
|
662 |
+
this_.check_holder_compat();
|
663 |
+
|
664 |
+
PyTypeObject *srctype = Py_TYPE(src.ptr());
|
665 |
+
|
666 |
+
// Case 1: If src is an exact type match for the target type then we can reinterpret_cast
|
667 |
+
// the instance's value pointer to the target type:
|
668 |
+
if (srctype == typeinfo->type) {
|
669 |
+
this_.load_value(reinterpret_cast<instance *>(src.ptr())->get_value_and_holder());
|
670 |
+
return true;
|
671 |
+
}
|
672 |
+
// Case 2: We have a derived class
|
673 |
+
if (PyType_IsSubtype(srctype, typeinfo->type)) {
|
674 |
+
auto &bases = all_type_info(srctype);
|
675 |
+
bool no_cpp_mi = typeinfo->simple_type;
|
676 |
+
|
677 |
+
// Case 2a: the python type is a Python-inherited derived class that inherits from just
|
678 |
+
// one simple (no MI) pybind11 class, or is an exact match, so the C++ instance is of
|
679 |
+
// the right type and we can use reinterpret_cast.
|
680 |
+
// (This is essentially the same as case 2b, but because not using multiple inheritance
|
681 |
+
// is extremely common, we handle it specially to avoid the loop iterator and type
|
682 |
+
// pointer lookup overhead)
|
683 |
+
if (bases.size() == 1 && (no_cpp_mi || bases.front()->type == typeinfo->type)) {
|
684 |
+
this_.load_value(reinterpret_cast<instance *>(src.ptr())->get_value_and_holder());
|
685 |
+
return true;
|
686 |
+
}
|
687 |
+
// Case 2b: the python type inherits from multiple C++ bases. Check the bases to see if
|
688 |
+
// we can find an exact match (or, for a simple C++ type, an inherited match); if so, we
|
689 |
+
// can safely reinterpret_cast to the relevant pointer.
|
690 |
+
if (bases.size() > 1) {
|
691 |
+
for (auto base : bases) {
|
692 |
+
if (no_cpp_mi ? PyType_IsSubtype(base->type, typeinfo->type) : base->type == typeinfo->type) {
|
693 |
+
this_.load_value(reinterpret_cast<instance *>(src.ptr())->get_value_and_holder(base));
|
694 |
+
return true;
|
695 |
+
}
|
696 |
+
}
|
697 |
+
}
|
698 |
+
|
699 |
+
// Case 2c: C++ multiple inheritance is involved and we couldn't find an exact type match
|
700 |
+
// in the registered bases, above, so try implicit casting (needed for proper C++ casting
|
701 |
+
// when MI is involved).
|
702 |
+
if (this_.try_implicit_casts(src, convert))
|
703 |
+
return true;
|
704 |
+
}
|
705 |
+
|
706 |
+
// Perform an implicit conversion
|
707 |
+
if (convert) {
|
708 |
+
for (auto &converter : typeinfo->implicit_conversions) {
|
709 |
+
auto temp = reinterpret_steal<object>(converter(src.ptr(), typeinfo->type));
|
710 |
+
if (load_impl<ThisT>(temp, false)) {
|
711 |
+
loader_life_support::add_patient(temp);
|
712 |
+
return true;
|
713 |
+
}
|
714 |
+
}
|
715 |
+
if (this_.try_direct_conversions(src))
|
716 |
+
return true;
|
717 |
+
}
|
718 |
+
|
719 |
+
// Failed to match local typeinfo. Try again with global.
|
720 |
+
if (typeinfo->module_local) {
|
721 |
+
if (auto gtype = get_global_type_info(*typeinfo->cpptype)) {
|
722 |
+
typeinfo = gtype;
|
723 |
+
return load(src, false);
|
724 |
+
}
|
725 |
+
}
|
726 |
+
|
727 |
+
// Global typeinfo has precedence over foreign module_local
|
728 |
+
if (try_load_foreign_module_local(src)) {
|
729 |
+
return true;
|
730 |
+
}
|
731 |
+
|
732 |
+
// Custom converters didn't take None, now we convert None to nullptr.
|
733 |
+
if (src.is_none()) {
|
734 |
+
// Defer accepting None to other overloads (if we aren't in convert mode):
|
735 |
+
if (!convert) return false;
|
736 |
+
value = nullptr;
|
737 |
+
return true;
|
738 |
+
}
|
739 |
+
|
740 |
+
return false;
|
741 |
+
}
|
742 |
+
|
743 |
+
|
744 |
+
// Called to do type lookup and wrap the pointer and type in a pair when a dynamic_cast
|
745 |
+
// isn't needed or can't be used. If the type is unknown, sets the error and returns a pair
|
746 |
+
// with .second = nullptr. (p.first = nullptr is not an error: it becomes None).
|
747 |
+
PYBIND11_NOINLINE static std::pair<const void *, const type_info *> src_and_type(
|
748 |
+
const void *src, const std::type_info &cast_type, const std::type_info *rtti_type = nullptr) {
|
749 |
+
if (auto *tpi = get_type_info(cast_type))
|
750 |
+
return {src, const_cast<const type_info *>(tpi)};
|
751 |
+
|
752 |
+
// Not found, set error:
|
753 |
+
std::string tname = rtti_type ? rtti_type->name() : cast_type.name();
|
754 |
+
detail::clean_type_id(tname);
|
755 |
+
std::string msg = "Unregistered type : " + tname;
|
756 |
+
PyErr_SetString(PyExc_TypeError, msg.c_str());
|
757 |
+
return {nullptr, nullptr};
|
758 |
+
}
|
759 |
+
|
760 |
+
const type_info *typeinfo = nullptr;
|
761 |
+
const std::type_info *cpptype = nullptr;
|
762 |
+
void *value = nullptr;
|
763 |
+
};
|
764 |
+
|
765 |
+
/**
|
766 |
+
* Determine suitable casting operator for pointer-or-lvalue-casting type casters. The type caster
|
767 |
+
* needs to provide `operator T*()` and `operator T&()` operators.
|
768 |
+
*
|
769 |
+
* If the type supports moving the value away via an `operator T&&() &&` method, it should use
|
770 |
+
* `movable_cast_op_type` instead.
|
771 |
+
*/
|
772 |
+
template <typename T>
|
773 |
+
using cast_op_type =
|
774 |
+
conditional_t<std::is_pointer<remove_reference_t<T>>::value,
|
775 |
+
typename std::add_pointer<intrinsic_t<T>>::type,
|
776 |
+
typename std::add_lvalue_reference<intrinsic_t<T>>::type>;
|
777 |
+
|
778 |
+
/**
|
779 |
+
* Determine suitable casting operator for a type caster with a movable value. Such a type caster
|
780 |
+
* needs to provide `operator T*()`, `operator T&()`, and `operator T&&() &&`. The latter will be
|
781 |
+
* called in appropriate contexts where the value can be moved rather than copied.
|
782 |
+
*
|
783 |
+
* These operator are automatically provided when using the PYBIND11_TYPE_CASTER macro.
|
784 |
+
*/
|
785 |
+
template <typename T>
|
786 |
+
using movable_cast_op_type =
|
787 |
+
conditional_t<std::is_pointer<typename std::remove_reference<T>::type>::value,
|
788 |
+
typename std::add_pointer<intrinsic_t<T>>::type,
|
789 |
+
conditional_t<std::is_rvalue_reference<T>::value,
|
790 |
+
typename std::add_rvalue_reference<intrinsic_t<T>>::type,
|
791 |
+
typename std::add_lvalue_reference<intrinsic_t<T>>::type>>;
|
792 |
+
|
793 |
+
// std::is_copy_constructible isn't quite enough: it lets std::vector<T> (and similar) through when
|
794 |
+
// T is non-copyable, but code containing such a copy constructor fails to actually compile.
|
795 |
+
template <typename T, typename SFINAE = void> struct is_copy_constructible : std::is_copy_constructible<T> {};
|
796 |
+
|
797 |
+
// Specialization for types that appear to be copy constructible but also look like stl containers
|
798 |
+
// (we specifically check for: has `value_type` and `reference` with `reference = value_type&`): if
|
799 |
+
// so, copy constructability depends on whether the value_type is copy constructible.
|
800 |
+
template <typename Container> struct is_copy_constructible<Container, enable_if_t<all_of<
|
801 |
+
std::is_copy_constructible<Container>,
|
802 |
+
std::is_same<typename Container::value_type &, typename Container::reference>,
|
803 |
+
// Avoid infinite recursion
|
804 |
+
negation<std::is_same<Container, typename Container::value_type>>
|
805 |
+
>::value>> : is_copy_constructible<typename Container::value_type> {};
|
806 |
+
|
807 |
+
// Likewise for std::pair
|
808 |
+
// (after C++17 it is mandatory that the copy constructor not exist when the two types aren't themselves
|
809 |
+
// copy constructible, but this can not be relied upon when T1 or T2 are themselves containers).
|
810 |
+
template <typename T1, typename T2> struct is_copy_constructible<std::pair<T1, T2>>
|
811 |
+
: all_of<is_copy_constructible<T1>, is_copy_constructible<T2>> {};
|
812 |
+
|
813 |
+
// The same problems arise with std::is_copy_assignable, so we use the same workaround.
|
814 |
+
template <typename T, typename SFINAE = void> struct is_copy_assignable : std::is_copy_assignable<T> {};
|
815 |
+
template <typename Container> struct is_copy_assignable<Container, enable_if_t<all_of<
|
816 |
+
std::is_copy_assignable<Container>,
|
817 |
+
std::is_same<typename Container::value_type &, typename Container::reference>
|
818 |
+
>::value>> : is_copy_assignable<typename Container::value_type> {};
|
819 |
+
template <typename T1, typename T2> struct is_copy_assignable<std::pair<T1, T2>>
|
820 |
+
: all_of<is_copy_assignable<T1>, is_copy_assignable<T2>> {};
|
821 |
+
|
822 |
+
PYBIND11_NAMESPACE_END(detail)
|
823 |
+
|
824 |
+
// polymorphic_type_hook<itype>::get(src, tinfo) determines whether the object pointed
|
825 |
+
// to by `src` actually is an instance of some class derived from `itype`.
|
826 |
+
// If so, it sets `tinfo` to point to the std::type_info representing that derived
|
827 |
+
// type, and returns a pointer to the start of the most-derived object of that type
|
828 |
+
// (in which `src` is a subobject; this will be the same address as `src` in most
|
829 |
+
// single inheritance cases). If not, or if `src` is nullptr, it simply returns `src`
|
830 |
+
// and leaves `tinfo` at its default value of nullptr.
|
831 |
+
//
|
832 |
+
// The default polymorphic_type_hook just returns src. A specialization for polymorphic
|
833 |
+
// types determines the runtime type of the passed object and adjusts the this-pointer
|
834 |
+
// appropriately via dynamic_cast<void*>. This is what enables a C++ Animal* to appear
|
835 |
+
// to Python as a Dog (if Dog inherits from Animal, Animal is polymorphic, Dog is
|
836 |
+
// registered with pybind11, and this Animal is in fact a Dog).
|
837 |
+
//
|
838 |
+
// You may specialize polymorphic_type_hook yourself for types that want to appear
|
839 |
+
// polymorphic to Python but do not use C++ RTTI. (This is a not uncommon pattern
|
840 |
+
// in performance-sensitive applications, used most notably in LLVM.)
|
841 |
+
//
|
842 |
+
// polymorphic_type_hook_base allows users to specialize polymorphic_type_hook with
|
843 |
+
// std::enable_if. User provided specializations will always have higher priority than
|
844 |
+
// the default implementation and specialization provided in polymorphic_type_hook_base.
|
845 |
+
template <typename itype, typename SFINAE = void>
|
846 |
+
struct polymorphic_type_hook_base
|
847 |
+
{
|
848 |
+
static const void *get(const itype *src, const std::type_info*&) { return src; }
|
849 |
+
};
|
850 |
+
template <typename itype>
|
851 |
+
struct polymorphic_type_hook_base<itype, detail::enable_if_t<std::is_polymorphic<itype>::value>>
|
852 |
+
{
|
853 |
+
static const void *get(const itype *src, const std::type_info*& type) {
|
854 |
+
type = src ? &typeid(*src) : nullptr;
|
855 |
+
return dynamic_cast<const void*>(src);
|
856 |
+
}
|
857 |
+
};
|
858 |
+
template <typename itype, typename SFINAE = void>
|
859 |
+
struct polymorphic_type_hook : public polymorphic_type_hook_base<itype> {};
|
860 |
+
|
861 |
+
PYBIND11_NAMESPACE_BEGIN(detail)
|
862 |
+
|
863 |
+
/// Generic type caster for objects stored on the heap
|
864 |
+
template <typename type> class type_caster_base : public type_caster_generic {
|
865 |
+
using itype = intrinsic_t<type>;
|
866 |
+
|
867 |
+
public:
|
868 |
+
static constexpr auto name = _<type>();
|
869 |
+
|
870 |
+
type_caster_base() : type_caster_base(typeid(type)) { }
|
871 |
+
explicit type_caster_base(const std::type_info &info) : type_caster_generic(info) { }
|
872 |
+
|
873 |
+
static handle cast(const itype &src, return_value_policy policy, handle parent) {
|
874 |
+
if (policy == return_value_policy::automatic || policy == return_value_policy::automatic_reference)
|
875 |
+
policy = return_value_policy::copy;
|
876 |
+
return cast(&src, policy, parent);
|
877 |
+
}
|
878 |
+
|
879 |
+
static handle cast(itype &&src, return_value_policy, handle parent) {
|
880 |
+
return cast(&src, return_value_policy::move, parent);
|
881 |
+
}
|
882 |
+
|
883 |
+
// Returns a (pointer, type_info) pair taking care of necessary type lookup for a
|
884 |
+
// polymorphic type (using RTTI by default, but can be overridden by specializing
|
885 |
+
// polymorphic_type_hook). If the instance isn't derived, returns the base version.
|
886 |
+
static std::pair<const void *, const type_info *> src_and_type(const itype *src) {
|
887 |
+
auto &cast_type = typeid(itype);
|
888 |
+
const std::type_info *instance_type = nullptr;
|
889 |
+
const void *vsrc = polymorphic_type_hook<itype>::get(src, instance_type);
|
890 |
+
if (instance_type && !same_type(cast_type, *instance_type)) {
|
891 |
+
// This is a base pointer to a derived type. If the derived type is registered
|
892 |
+
// with pybind11, we want to make the full derived object available.
|
893 |
+
// In the typical case where itype is polymorphic, we get the correct
|
894 |
+
// derived pointer (which may be != base pointer) by a dynamic_cast to
|
895 |
+
// most derived type. If itype is not polymorphic, we won't get here
|
896 |
+
// except via a user-provided specialization of polymorphic_type_hook,
|
897 |
+
// and the user has promised that no this-pointer adjustment is
|
898 |
+
// required in that case, so it's OK to use static_cast.
|
899 |
+
if (const auto *tpi = get_type_info(*instance_type))
|
900 |
+
return {vsrc, tpi};
|
901 |
+
}
|
902 |
+
// Otherwise we have either a nullptr, an `itype` pointer, or an unknown derived pointer, so
|
903 |
+
// don't do a cast
|
904 |
+
return type_caster_generic::src_and_type(src, cast_type, instance_type);
|
905 |
+
}
|
906 |
+
|
907 |
+
static handle cast(const itype *src, return_value_policy policy, handle parent) {
|
908 |
+
auto st = src_and_type(src);
|
909 |
+
return type_caster_generic::cast(
|
910 |
+
st.first, policy, parent, st.second,
|
911 |
+
make_copy_constructor(src), make_move_constructor(src));
|
912 |
+
}
|
913 |
+
|
914 |
+
static handle cast_holder(const itype *src, const void *holder) {
|
915 |
+
auto st = src_and_type(src);
|
916 |
+
return type_caster_generic::cast(
|
917 |
+
st.first, return_value_policy::take_ownership, {}, st.second,
|
918 |
+
nullptr, nullptr, holder);
|
919 |
+
}
|
920 |
+
|
921 |
+
template <typename T> using cast_op_type = detail::cast_op_type<T>;
|
922 |
+
|
923 |
+
operator itype*() { return (type *) value; }
|
924 |
+
operator itype&() { if (!value) throw reference_cast_error(); return *((itype *) value); }
|
925 |
+
|
926 |
+
protected:
|
927 |
+
using Constructor = void *(*)(const void *);
|
928 |
+
|
929 |
+
/* Only enabled when the types are {copy,move}-constructible *and* when the type
|
930 |
+
does not have a private operator new implementation. */
|
931 |
+
template <typename T, typename = enable_if_t<is_copy_constructible<T>::value>>
|
932 |
+
static auto make_copy_constructor(const T *x) -> decltype(new T(*x), Constructor{}) {
|
933 |
+
return [](const void *arg) -> void * {
|
934 |
+
return new T(*reinterpret_cast<const T *>(arg));
|
935 |
+
};
|
936 |
+
}
|
937 |
+
|
938 |
+
template <typename T, typename = enable_if_t<std::is_move_constructible<T>::value>>
|
939 |
+
static auto make_move_constructor(const T *x) -> decltype(new T(std::move(*const_cast<T *>(x))), Constructor{}) {
|
940 |
+
return [](const void *arg) -> void * {
|
941 |
+
return new T(std::move(*const_cast<T *>(reinterpret_cast<const T *>(arg))));
|
942 |
+
};
|
943 |
+
}
|
944 |
+
|
945 |
+
static Constructor make_copy_constructor(...) { return nullptr; }
|
946 |
+
static Constructor make_move_constructor(...) { return nullptr; }
|
947 |
+
};
|
948 |
+
|
949 |
+
PYBIND11_NAMESPACE_END(detail)
|
950 |
+
PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)
|
third-party/DPVO/Pangolin/components/pango_python/pybind11/include/pybind11/detail/typeid.h
ADDED
@@ -0,0 +1,55 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/*
|
2 |
+
pybind11/detail/typeid.h: Compiler-independent access to type identifiers
|
3 |
+
|
4 |
+
Copyright (c) 2016 Wenzel Jakob <[email protected]>
|
5 |
+
|
6 |
+
All rights reserved. Use of this source code is governed by a
|
7 |
+
BSD-style license that can be found in the LICENSE file.
|
8 |
+
*/
|
9 |
+
|
10 |
+
#pragma once
|
11 |
+
|
12 |
+
#include <cstdio>
|
13 |
+
#include <cstdlib>
|
14 |
+
|
15 |
+
#if defined(__GNUG__)
|
16 |
+
#include <cxxabi.h>
|
17 |
+
#endif
|
18 |
+
|
19 |
+
#include "common.h"
|
20 |
+
|
21 |
+
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
|
22 |
+
PYBIND11_NAMESPACE_BEGIN(detail)
|
23 |
+
/// Erase all occurrences of a substring
|
24 |
+
inline void erase_all(std::string &string, const std::string &search) {
|
25 |
+
for (size_t pos = 0;;) {
|
26 |
+
pos = string.find(search, pos);
|
27 |
+
if (pos == std::string::npos) break;
|
28 |
+
string.erase(pos, search.length());
|
29 |
+
}
|
30 |
+
}
|
31 |
+
|
32 |
+
PYBIND11_NOINLINE inline void clean_type_id(std::string &name) {
|
33 |
+
#if defined(__GNUG__)
|
34 |
+
int status = 0;
|
35 |
+
std::unique_ptr<char, void (*)(void *)> res {
|
36 |
+
abi::__cxa_demangle(name.c_str(), nullptr, nullptr, &status), std::free };
|
37 |
+
if (status == 0)
|
38 |
+
name = res.get();
|
39 |
+
#else
|
40 |
+
detail::erase_all(name, "class ");
|
41 |
+
detail::erase_all(name, "struct ");
|
42 |
+
detail::erase_all(name, "enum ");
|
43 |
+
#endif
|
44 |
+
detail::erase_all(name, "pybind11::");
|
45 |
+
}
|
46 |
+
PYBIND11_NAMESPACE_END(detail)
|
47 |
+
|
48 |
+
/// Return a string representation of a C++ type
|
49 |
+
template <typename T> static std::string type_id() {
|
50 |
+
std::string name(typeid(T).name());
|
51 |
+
detail::clean_type_id(name);
|
52 |
+
return name;
|
53 |
+
}
|
54 |
+
|
55 |
+
PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)
|
third-party/DPVO/Pangolin/components/pango_python/pybind11/include/pybind11/eigen.h
ADDED
@@ -0,0 +1,604 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/*
|
2 |
+
pybind11/eigen.h: Transparent conversion for dense and sparse Eigen matrices
|
3 |
+
|
4 |
+
Copyright (c) 2016 Wenzel Jakob <[email protected]>
|
5 |
+
|
6 |
+
All rights reserved. Use of this source code is governed by a
|
7 |
+
BSD-style license that can be found in the LICENSE file.
|
8 |
+
*/
|
9 |
+
|
10 |
+
#pragma once
|
11 |
+
|
12 |
+
#include "numpy.h"
|
13 |
+
|
14 |
+
#if defined(__INTEL_COMPILER)
|
15 |
+
# pragma warning(disable: 1682) // implicit conversion of a 64-bit integral type to a smaller integral type (potential portability problem)
|
16 |
+
#elif defined(__GNUG__) || defined(__clang__)
|
17 |
+
# pragma GCC diagnostic push
|
18 |
+
# pragma GCC diagnostic ignored "-Wconversion"
|
19 |
+
# pragma GCC diagnostic ignored "-Wdeprecated-declarations"
|
20 |
+
# ifdef __clang__
|
21 |
+
// Eigen generates a bunch of implicit-copy-constructor-is-deprecated warnings with -Wdeprecated
|
22 |
+
// under Clang, so disable that warning here:
|
23 |
+
# pragma GCC diagnostic ignored "-Wdeprecated"
|
24 |
+
# endif
|
25 |
+
# if __GNUC__ >= 7
|
26 |
+
# pragma GCC diagnostic ignored "-Wint-in-bool-context"
|
27 |
+
# endif
|
28 |
+
#endif
|
29 |
+
|
30 |
+
#if defined(_MSC_VER)
|
31 |
+
# pragma warning(push)
|
32 |
+
# pragma warning(disable: 4127) // warning C4127: Conditional expression is constant
|
33 |
+
# pragma warning(disable: 4996) // warning C4996: std::unary_negate is deprecated in C++17
|
34 |
+
#endif
|
35 |
+
|
36 |
+
#include <Eigen/Core>
|
37 |
+
#include <Eigen/SparseCore>
|
38 |
+
|
39 |
+
// Eigen prior to 3.2.7 doesn't have proper move constructors--but worse, some classes get implicit
|
40 |
+
// move constructors that break things. We could detect this an explicitly copy, but an extra copy
|
41 |
+
// of matrices seems highly undesirable.
|
42 |
+
static_assert(EIGEN_VERSION_AT_LEAST(3,2,7), "Eigen support in pybind11 requires Eigen >= 3.2.7");
|
43 |
+
|
44 |
+
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
|
45 |
+
|
46 |
+
// Provide a convenience alias for easier pass-by-ref usage with fully dynamic strides:
|
47 |
+
using EigenDStride = Eigen::Stride<Eigen::Dynamic, Eigen::Dynamic>;
|
48 |
+
template <typename MatrixType> using EigenDRef = Eigen::Ref<MatrixType, 0, EigenDStride>;
|
49 |
+
template <typename MatrixType> using EigenDMap = Eigen::Map<MatrixType, 0, EigenDStride>;
|
50 |
+
|
51 |
+
PYBIND11_NAMESPACE_BEGIN(detail)
|
52 |
+
|
53 |
+
#if EIGEN_VERSION_AT_LEAST(3,3,0)
|
54 |
+
using EigenIndex = Eigen::Index;
|
55 |
+
#else
|
56 |
+
using EigenIndex = EIGEN_DEFAULT_DENSE_INDEX_TYPE;
|
57 |
+
#endif
|
58 |
+
|
59 |
+
// Matches Eigen::Map, Eigen::Ref, blocks, etc:
|
60 |
+
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>>;
|
61 |
+
template <typename T> using is_eigen_mutable_map = std::is_base_of<Eigen::MapBase<T, Eigen::WriteAccessors>, T>;
|
62 |
+
template <typename T> using is_eigen_dense_plain = all_of<negation<is_eigen_dense_map<T>>, is_template_base_of<Eigen::PlainObjectBase, T>>;
|
63 |
+
template <typename T> using is_eigen_sparse = is_template_base_of<Eigen::SparseMatrixBase, T>;
|
64 |
+
// Test for objects inheriting from EigenBase<Derived> that aren't captured by the above. This
|
65 |
+
// basically covers anything that can be assigned to a dense matrix but that don't have a typical
|
66 |
+
// matrix data layout that can be copied from their .data(). For example, DiagonalMatrix and
|
67 |
+
// SelfAdjointView fall into this category.
|
68 |
+
template <typename T> using is_eigen_other = all_of<
|
69 |
+
is_template_base_of<Eigen::EigenBase, T>,
|
70 |
+
negation<any_of<is_eigen_dense_map<T>, is_eigen_dense_plain<T>, is_eigen_sparse<T>>>
|
71 |
+
>;
|
72 |
+
|
73 |
+
// Captures numpy/eigen conformability status (returned by EigenProps::conformable()):
|
74 |
+
template <bool EigenRowMajor> struct EigenConformable {
|
75 |
+
bool conformable = false;
|
76 |
+
EigenIndex rows = 0, cols = 0;
|
77 |
+
EigenDStride stride{0, 0}; // Only valid if negativestrides is false!
|
78 |
+
bool negativestrides = false; // If true, do not use stride!
|
79 |
+
|
80 |
+
EigenConformable(bool fits = false) : conformable{fits} {}
|
81 |
+
// Matrix type:
|
82 |
+
EigenConformable(EigenIndex r, EigenIndex c,
|
83 |
+
EigenIndex rstride, EigenIndex cstride) :
|
84 |
+
conformable{true}, rows{r}, cols{c} {
|
85 |
+
// TODO: when Eigen bug #747 is fixed, remove the tests for non-negativity. http://eigen.tuxfamily.org/bz/show_bug.cgi?id=747
|
86 |
+
if (rstride < 0 || cstride < 0) {
|
87 |
+
negativestrides = true;
|
88 |
+
} else {
|
89 |
+
stride = {EigenRowMajor ? rstride : cstride /* outer stride */,
|
90 |
+
EigenRowMajor ? cstride : rstride /* inner stride */ };
|
91 |
+
}
|
92 |
+
}
|
93 |
+
// Vector type:
|
94 |
+
EigenConformable(EigenIndex r, EigenIndex c, EigenIndex stride)
|
95 |
+
: EigenConformable(r, c, r == 1 ? c*stride : stride, c == 1 ? r : r*stride) {}
|
96 |
+
|
97 |
+
template <typename props> bool stride_compatible() const {
|
98 |
+
// To have compatible strides, we need (on both dimensions) one of fully dynamic strides,
|
99 |
+
// matching strides, or a dimension size of 1 (in which case the stride value is irrelevant)
|
100 |
+
return
|
101 |
+
!negativestrides &&
|
102 |
+
(props::inner_stride == Eigen::Dynamic || props::inner_stride == stride.inner() ||
|
103 |
+
(EigenRowMajor ? cols : rows) == 1) &&
|
104 |
+
(props::outer_stride == Eigen::Dynamic || props::outer_stride == stride.outer() ||
|
105 |
+
(EigenRowMajor ? rows : cols) == 1);
|
106 |
+
}
|
107 |
+
operator bool() const { return conformable; }
|
108 |
+
};
|
109 |
+
|
110 |
+
template <typename Type> struct eigen_extract_stride { using type = Type; };
|
111 |
+
template <typename PlainObjectType, int MapOptions, typename StrideType>
|
112 |
+
struct eigen_extract_stride<Eigen::Map<PlainObjectType, MapOptions, StrideType>> { using type = StrideType; };
|
113 |
+
template <typename PlainObjectType, int Options, typename StrideType>
|
114 |
+
struct eigen_extract_stride<Eigen::Ref<PlainObjectType, Options, StrideType>> { using type = StrideType; };
|
115 |
+
|
116 |
+
// Helper struct for extracting information from an Eigen type
|
117 |
+
template <typename Type_> struct EigenProps {
|
118 |
+
using Type = Type_;
|
119 |
+
using Scalar = typename Type::Scalar;
|
120 |
+
using StrideType = typename eigen_extract_stride<Type>::type;
|
121 |
+
static constexpr EigenIndex
|
122 |
+
rows = Type::RowsAtCompileTime,
|
123 |
+
cols = Type::ColsAtCompileTime,
|
124 |
+
size = Type::SizeAtCompileTime;
|
125 |
+
static constexpr bool
|
126 |
+
row_major = Type::IsRowMajor,
|
127 |
+
vector = Type::IsVectorAtCompileTime, // At least one dimension has fixed size 1
|
128 |
+
fixed_rows = rows != Eigen::Dynamic,
|
129 |
+
fixed_cols = cols != Eigen::Dynamic,
|
130 |
+
fixed = size != Eigen::Dynamic, // Fully-fixed size
|
131 |
+
dynamic = !fixed_rows && !fixed_cols; // Fully-dynamic size
|
132 |
+
|
133 |
+
template <EigenIndex i, EigenIndex ifzero> using if_zero = std::integral_constant<EigenIndex, i == 0 ? ifzero : i>;
|
134 |
+
static constexpr EigenIndex inner_stride = if_zero<StrideType::InnerStrideAtCompileTime, 1>::value,
|
135 |
+
outer_stride = if_zero<StrideType::OuterStrideAtCompileTime,
|
136 |
+
vector ? size : row_major ? cols : rows>::value;
|
137 |
+
static constexpr bool dynamic_stride = inner_stride == Eigen::Dynamic && outer_stride == Eigen::Dynamic;
|
138 |
+
static constexpr bool requires_row_major = !dynamic_stride && !vector && (row_major ? inner_stride : outer_stride) == 1;
|
139 |
+
static constexpr bool requires_col_major = !dynamic_stride && !vector && (row_major ? outer_stride : inner_stride) == 1;
|
140 |
+
|
141 |
+
// Takes an input array and determines whether we can make it fit into the Eigen type. If
|
142 |
+
// the array is a vector, we attempt to fit it into either an Eigen 1xN or Nx1 vector
|
143 |
+
// (preferring the latter if it will fit in either, i.e. for a fully dynamic matrix type).
|
144 |
+
static EigenConformable<row_major> conformable(const array &a) {
|
145 |
+
const auto dims = a.ndim();
|
146 |
+
if (dims < 1 || dims > 2)
|
147 |
+
return false;
|
148 |
+
|
149 |
+
if (dims == 2) { // Matrix type: require exact match (or dynamic)
|
150 |
+
|
151 |
+
EigenIndex
|
152 |
+
np_rows = a.shape(0),
|
153 |
+
np_cols = a.shape(1),
|
154 |
+
np_rstride = a.strides(0) / static_cast<ssize_t>(sizeof(Scalar)),
|
155 |
+
np_cstride = a.strides(1) / static_cast<ssize_t>(sizeof(Scalar));
|
156 |
+
if ((fixed_rows && np_rows != rows) || (fixed_cols && np_cols != cols))
|
157 |
+
return false;
|
158 |
+
|
159 |
+
return {np_rows, np_cols, np_rstride, np_cstride};
|
160 |
+
}
|
161 |
+
|
162 |
+
// Otherwise we're storing an n-vector. Only one of the strides will be used, but whichever
|
163 |
+
// is used, we want the (single) numpy stride value.
|
164 |
+
const EigenIndex n = a.shape(0),
|
165 |
+
stride = a.strides(0) / static_cast<ssize_t>(sizeof(Scalar));
|
166 |
+
|
167 |
+
if (vector) { // Eigen type is a compile-time vector
|
168 |
+
if (fixed && size != n)
|
169 |
+
return false; // Vector size mismatch
|
170 |
+
return {rows == 1 ? 1 : n, cols == 1 ? 1 : n, stride};
|
171 |
+
}
|
172 |
+
if (fixed) {
|
173 |
+
// The type has a fixed size, but is not a vector: abort
|
174 |
+
return false;
|
175 |
+
}
|
176 |
+
if (fixed_cols) {
|
177 |
+
// Since this isn't a vector, cols must be != 1. We allow this only if it exactly
|
178 |
+
// equals the number of elements (rows is Dynamic, and so 1 row is allowed).
|
179 |
+
if (cols != n) return false;
|
180 |
+
return {1, n, stride};
|
181 |
+
} // Otherwise it's either fully dynamic, or column dynamic; both become a column vector
|
182 |
+
if (fixed_rows && rows != n) return false;
|
183 |
+
return {n, 1, stride};
|
184 |
+
}
|
185 |
+
|
186 |
+
static constexpr bool show_writeable = is_eigen_dense_map<Type>::value && is_eigen_mutable_map<Type>::value;
|
187 |
+
static constexpr bool show_order = is_eigen_dense_map<Type>::value;
|
188 |
+
static constexpr bool show_c_contiguous = show_order && requires_row_major;
|
189 |
+
static constexpr bool show_f_contiguous = !show_c_contiguous && show_order && requires_col_major;
|
190 |
+
|
191 |
+
static constexpr auto descriptor =
|
192 |
+
_("numpy.ndarray[") + npy_format_descriptor<Scalar>::name +
|
193 |
+
_("[") + _<fixed_rows>(_<(size_t) rows>(), _("m")) +
|
194 |
+
_(", ") + _<fixed_cols>(_<(size_t) cols>(), _("n")) +
|
195 |
+
_("]") +
|
196 |
+
// For a reference type (e.g. Ref<MatrixXd>) we have other constraints that might need to be
|
197 |
+
// satisfied: writeable=True (for a mutable reference), and, depending on the map's stride
|
198 |
+
// options, possibly f_contiguous or c_contiguous. We include them in the descriptor output
|
199 |
+
// to provide some hint as to why a TypeError is occurring (otherwise it can be confusing to
|
200 |
+
// see that a function accepts a 'numpy.ndarray[float64[3,2]]' and an error message that you
|
201 |
+
// *gave* a numpy.ndarray of the right type and dimensions.
|
202 |
+
_<show_writeable>(", flags.writeable", "") +
|
203 |
+
_<show_c_contiguous>(", flags.c_contiguous", "") +
|
204 |
+
_<show_f_contiguous>(", flags.f_contiguous", "") +
|
205 |
+
_("]");
|
206 |
+
};
|
207 |
+
|
208 |
+
// Casts an Eigen type to numpy array. If given a base, the numpy array references the src data,
|
209 |
+
// otherwise it'll make a copy. writeable lets you turn off the writeable flag for the array.
|
210 |
+
template <typename props> handle eigen_array_cast(typename props::Type const &src, handle base = handle(), bool writeable = true) {
|
211 |
+
constexpr ssize_t elem_size = sizeof(typename props::Scalar);
|
212 |
+
array a;
|
213 |
+
if (props::vector)
|
214 |
+
a = array({ src.size() }, { elem_size * src.innerStride() }, src.data(), base);
|
215 |
+
else
|
216 |
+
a = array({ src.rows(), src.cols() }, { elem_size * src.rowStride(), elem_size * src.colStride() },
|
217 |
+
src.data(), base);
|
218 |
+
|
219 |
+
if (!writeable)
|
220 |
+
array_proxy(a.ptr())->flags &= ~detail::npy_api::NPY_ARRAY_WRITEABLE_;
|
221 |
+
|
222 |
+
return a.release();
|
223 |
+
}
|
224 |
+
|
225 |
+
// Takes an lvalue ref to some Eigen type and a (python) base object, creating a numpy array that
|
226 |
+
// reference the Eigen object's data with `base` as the python-registered base class (if omitted,
|
227 |
+
// the base will be set to None, and lifetime management is up to the caller). The numpy array is
|
228 |
+
// non-writeable if the given type is const.
|
229 |
+
template <typename props, typename Type>
|
230 |
+
handle eigen_ref_array(Type &src, handle parent = none()) {
|
231 |
+
// none here is to get past array's should-we-copy detection, which currently always
|
232 |
+
// copies when there is no base. Setting the base to None should be harmless.
|
233 |
+
return eigen_array_cast<props>(src, parent, !std::is_const<Type>::value);
|
234 |
+
}
|
235 |
+
|
236 |
+
// Takes a pointer to some dense, plain Eigen type, builds a capsule around it, then returns a numpy
|
237 |
+
// array that references the encapsulated data with a python-side reference to the capsule to tie
|
238 |
+
// its destruction to that of any dependent python objects. Const-ness is determined by whether or
|
239 |
+
// not the Type of the pointer given is const.
|
240 |
+
template <typename props, typename Type, typename = enable_if_t<is_eigen_dense_plain<Type>::value>>
|
241 |
+
handle eigen_encapsulate(Type *src) {
|
242 |
+
capsule base(src, [](void *o) { delete static_cast<Type *>(o); });
|
243 |
+
return eigen_ref_array<props>(*src, base);
|
244 |
+
}
|
245 |
+
|
246 |
+
// Type caster for regular, dense matrix types (e.g. MatrixXd), but not maps/refs/etc. of dense
|
247 |
+
// types.
|
248 |
+
template<typename Type>
|
249 |
+
struct type_caster<Type, enable_if_t<is_eigen_dense_plain<Type>::value>> {
|
250 |
+
using Scalar = typename Type::Scalar;
|
251 |
+
using props = EigenProps<Type>;
|
252 |
+
|
253 |
+
bool load(handle src, bool convert) {
|
254 |
+
// If we're in no-convert mode, only load if given an array of the correct type
|
255 |
+
if (!convert && !isinstance<array_t<Scalar>>(src))
|
256 |
+
return false;
|
257 |
+
|
258 |
+
// Coerce into an array, but don't do type conversion yet; the copy below handles it.
|
259 |
+
auto buf = array::ensure(src);
|
260 |
+
|
261 |
+
if (!buf)
|
262 |
+
return false;
|
263 |
+
|
264 |
+
auto dims = buf.ndim();
|
265 |
+
if (dims < 1 || dims > 2)
|
266 |
+
return false;
|
267 |
+
|
268 |
+
auto fits = props::conformable(buf);
|
269 |
+
if (!fits)
|
270 |
+
return false;
|
271 |
+
|
272 |
+
// Allocate the new type, then build a numpy reference into it
|
273 |
+
value = Type(fits.rows, fits.cols);
|
274 |
+
auto ref = reinterpret_steal<array>(eigen_ref_array<props>(value));
|
275 |
+
if (dims == 1) ref = ref.squeeze();
|
276 |
+
else if (ref.ndim() == 1) buf = buf.squeeze();
|
277 |
+
|
278 |
+
int result = detail::npy_api::get().PyArray_CopyInto_(ref.ptr(), buf.ptr());
|
279 |
+
|
280 |
+
if (result < 0) { // Copy failed!
|
281 |
+
PyErr_Clear();
|
282 |
+
return false;
|
283 |
+
}
|
284 |
+
|
285 |
+
return true;
|
286 |
+
}
|
287 |
+
|
288 |
+
private:
|
289 |
+
|
290 |
+
// Cast implementation
|
291 |
+
template <typename CType>
|
292 |
+
static handle cast_impl(CType *src, return_value_policy policy, handle parent) {
|
293 |
+
switch (policy) {
|
294 |
+
case return_value_policy::take_ownership:
|
295 |
+
case return_value_policy::automatic:
|
296 |
+
return eigen_encapsulate<props>(src);
|
297 |
+
case return_value_policy::move:
|
298 |
+
return eigen_encapsulate<props>(new CType(std::move(*src)));
|
299 |
+
case return_value_policy::copy:
|
300 |
+
return eigen_array_cast<props>(*src);
|
301 |
+
case return_value_policy::reference:
|
302 |
+
case return_value_policy::automatic_reference:
|
303 |
+
return eigen_ref_array<props>(*src);
|
304 |
+
case return_value_policy::reference_internal:
|
305 |
+
return eigen_ref_array<props>(*src, parent);
|
306 |
+
default:
|
307 |
+
throw cast_error("unhandled return_value_policy: should not happen!");
|
308 |
+
};
|
309 |
+
}
|
310 |
+
|
311 |
+
public:
|
312 |
+
|
313 |
+
// Normal returned non-reference, non-const value:
|
314 |
+
static handle cast(Type &&src, return_value_policy /* policy */, handle parent) {
|
315 |
+
return cast_impl(&src, return_value_policy::move, parent);
|
316 |
+
}
|
317 |
+
// If you return a non-reference const, we mark the numpy array readonly:
|
318 |
+
static handle cast(const Type &&src, return_value_policy /* policy */, handle parent) {
|
319 |
+
return cast_impl(&src, return_value_policy::move, parent);
|
320 |
+
}
|
321 |
+
// lvalue reference return; default (automatic) becomes copy
|
322 |
+
static handle cast(Type &src, return_value_policy policy, handle parent) {
|
323 |
+
if (policy == return_value_policy::automatic || policy == return_value_policy::automatic_reference)
|
324 |
+
policy = return_value_policy::copy;
|
325 |
+
return cast_impl(&src, policy, parent);
|
326 |
+
}
|
327 |
+
// const lvalue reference return; default (automatic) becomes copy
|
328 |
+
static handle cast(const Type &src, return_value_policy policy, handle parent) {
|
329 |
+
if (policy == return_value_policy::automatic || policy == return_value_policy::automatic_reference)
|
330 |
+
policy = return_value_policy::copy;
|
331 |
+
return cast(&src, policy, parent);
|
332 |
+
}
|
333 |
+
// non-const pointer return
|
334 |
+
static handle cast(Type *src, return_value_policy policy, handle parent) {
|
335 |
+
return cast_impl(src, policy, parent);
|
336 |
+
}
|
337 |
+
// const pointer return
|
338 |
+
static handle cast(const Type *src, return_value_policy policy, handle parent) {
|
339 |
+
return cast_impl(src, policy, parent);
|
340 |
+
}
|
341 |
+
|
342 |
+
static constexpr auto name = props::descriptor;
|
343 |
+
|
344 |
+
operator Type*() { return &value; }
|
345 |
+
operator Type&() { return value; }
|
346 |
+
operator Type&&() && { return std::move(value); }
|
347 |
+
template <typename T> using cast_op_type = movable_cast_op_type<T>;
|
348 |
+
|
349 |
+
private:
|
350 |
+
Type value;
|
351 |
+
};
|
352 |
+
|
353 |
+
// Base class for casting reference/map/block/etc. objects back to python.
|
354 |
+
template <typename MapType> struct eigen_map_caster {
|
355 |
+
private:
|
356 |
+
using props = EigenProps<MapType>;
|
357 |
+
|
358 |
+
public:
|
359 |
+
|
360 |
+
// Directly referencing a ref/map's data is a bit dangerous (whatever the map/ref points to has
|
361 |
+
// to stay around), but we'll allow it under the assumption that you know what you're doing (and
|
362 |
+
// have an appropriate keep_alive in place). We return a numpy array pointing directly at the
|
363 |
+
// ref's data (The numpy array ends up read-only if the ref was to a const matrix type.) Note
|
364 |
+
// that this means you need to ensure you don't destroy the object in some other way (e.g. with
|
365 |
+
// an appropriate keep_alive, or with a reference to a statically allocated matrix).
|
366 |
+
static handle cast(const MapType &src, return_value_policy policy, handle parent) {
|
367 |
+
switch (policy) {
|
368 |
+
case return_value_policy::copy:
|
369 |
+
return eigen_array_cast<props>(src);
|
370 |
+
case return_value_policy::reference_internal:
|
371 |
+
return eigen_array_cast<props>(src, parent, is_eigen_mutable_map<MapType>::value);
|
372 |
+
case return_value_policy::reference:
|
373 |
+
case return_value_policy::automatic:
|
374 |
+
case return_value_policy::automatic_reference:
|
375 |
+
return eigen_array_cast<props>(src, none(), is_eigen_mutable_map<MapType>::value);
|
376 |
+
default:
|
377 |
+
// move, take_ownership don't make any sense for a ref/map:
|
378 |
+
pybind11_fail("Invalid return_value_policy for Eigen Map/Ref/Block type");
|
379 |
+
}
|
380 |
+
}
|
381 |
+
|
382 |
+
static constexpr auto name = props::descriptor;
|
383 |
+
|
384 |
+
// Explicitly delete these: support python -> C++ conversion on these (i.e. these can be return
|
385 |
+
// types but not bound arguments). We still provide them (with an explicitly delete) so that
|
386 |
+
// you end up here if you try anyway.
|
387 |
+
bool load(handle, bool) = delete;
|
388 |
+
operator MapType() = delete;
|
389 |
+
template <typename> using cast_op_type = MapType;
|
390 |
+
};
|
391 |
+
|
392 |
+
// We can return any map-like object (but can only load Refs, specialized next):
|
393 |
+
template <typename Type> struct type_caster<Type, enable_if_t<is_eigen_dense_map<Type>::value>>
|
394 |
+
: eigen_map_caster<Type> {};
|
395 |
+
|
396 |
+
// Loader for Ref<...> arguments. See the documentation for info on how to make this work without
|
397 |
+
// copying (it requires some extra effort in many cases).
|
398 |
+
template <typename PlainObjectType, typename StrideType>
|
399 |
+
struct type_caster<
|
400 |
+
Eigen::Ref<PlainObjectType, 0, StrideType>,
|
401 |
+
enable_if_t<is_eigen_dense_map<Eigen::Ref<PlainObjectType, 0, StrideType>>::value>
|
402 |
+
> : public eigen_map_caster<Eigen::Ref<PlainObjectType, 0, StrideType>> {
|
403 |
+
private:
|
404 |
+
using Type = Eigen::Ref<PlainObjectType, 0, StrideType>;
|
405 |
+
using props = EigenProps<Type>;
|
406 |
+
using Scalar = typename props::Scalar;
|
407 |
+
using MapType = Eigen::Map<PlainObjectType, 0, StrideType>;
|
408 |
+
using Array = array_t<Scalar, array::forcecast |
|
409 |
+
((props::row_major ? props::inner_stride : props::outer_stride) == 1 ? array::c_style :
|
410 |
+
(props::row_major ? props::outer_stride : props::inner_stride) == 1 ? array::f_style : 0)>;
|
411 |
+
static constexpr bool need_writeable = is_eigen_mutable_map<Type>::value;
|
412 |
+
// Delay construction (these have no default constructor)
|
413 |
+
std::unique_ptr<MapType> map;
|
414 |
+
std::unique_ptr<Type> ref;
|
415 |
+
// Our array. When possible, this is just a numpy array pointing to the source data, but
|
416 |
+
// sometimes we can't avoid copying (e.g. input is not a numpy array at all, has an incompatible
|
417 |
+
// layout, or is an array of a type that needs to be converted). Using a numpy temporary
|
418 |
+
// (rather than an Eigen temporary) saves an extra copy when we need both type conversion and
|
419 |
+
// storage order conversion. (Note that we refuse to use this temporary copy when loading an
|
420 |
+
// argument for a Ref<M> with M non-const, i.e. a read-write reference).
|
421 |
+
Array copy_or_ref;
|
422 |
+
public:
|
423 |
+
bool load(handle src, bool convert) {
|
424 |
+
// First check whether what we have is already an array of the right type. If not, we can't
|
425 |
+
// avoid a copy (because the copy is also going to do type conversion).
|
426 |
+
bool need_copy = !isinstance<Array>(src);
|
427 |
+
|
428 |
+
EigenConformable<props::row_major> fits;
|
429 |
+
if (!need_copy) {
|
430 |
+
// We don't need a converting copy, but we also need to check whether the strides are
|
431 |
+
// compatible with the Ref's stride requirements
|
432 |
+
auto aref = reinterpret_borrow<Array>(src);
|
433 |
+
|
434 |
+
if (aref && (!need_writeable || aref.writeable())) {
|
435 |
+
fits = props::conformable(aref);
|
436 |
+
if (!fits) return false; // Incompatible dimensions
|
437 |
+
if (!fits.template stride_compatible<props>())
|
438 |
+
need_copy = true;
|
439 |
+
else
|
440 |
+
copy_or_ref = std::move(aref);
|
441 |
+
}
|
442 |
+
else {
|
443 |
+
need_copy = true;
|
444 |
+
}
|
445 |
+
}
|
446 |
+
|
447 |
+
if (need_copy) {
|
448 |
+
// We need to copy: If we need a mutable reference, or we're not supposed to convert
|
449 |
+
// (either because we're in the no-convert overload pass, or because we're explicitly
|
450 |
+
// instructed not to copy (via `py::arg().noconvert()`) we have to fail loading.
|
451 |
+
if (!convert || need_writeable) return false;
|
452 |
+
|
453 |
+
Array copy = Array::ensure(src);
|
454 |
+
if (!copy) return false;
|
455 |
+
fits = props::conformable(copy);
|
456 |
+
if (!fits || !fits.template stride_compatible<props>())
|
457 |
+
return false;
|
458 |
+
copy_or_ref = std::move(copy);
|
459 |
+
loader_life_support::add_patient(copy_or_ref);
|
460 |
+
}
|
461 |
+
|
462 |
+
ref.reset();
|
463 |
+
map.reset(new MapType(data(copy_or_ref), fits.rows, fits.cols, make_stride(fits.stride.outer(), fits.stride.inner())));
|
464 |
+
ref.reset(new Type(*map));
|
465 |
+
|
466 |
+
return true;
|
467 |
+
}
|
468 |
+
|
469 |
+
operator Type*() { return ref.get(); }
|
470 |
+
operator Type&() { return *ref; }
|
471 |
+
template <typename _T> using cast_op_type = pybind11::detail::cast_op_type<_T>;
|
472 |
+
|
473 |
+
private:
|
474 |
+
template <typename T = Type, enable_if_t<is_eigen_mutable_map<T>::value, int> = 0>
|
475 |
+
Scalar *data(Array &a) { return a.mutable_data(); }
|
476 |
+
|
477 |
+
template <typename T = Type, enable_if_t<!is_eigen_mutable_map<T>::value, int> = 0>
|
478 |
+
const Scalar *data(Array &a) { return a.data(); }
|
479 |
+
|
480 |
+
// Attempt to figure out a constructor of `Stride` that will work.
|
481 |
+
// If both strides are fixed, use a default constructor:
|
482 |
+
template <typename S> using stride_ctor_default = bool_constant<
|
483 |
+
S::InnerStrideAtCompileTime != Eigen::Dynamic && S::OuterStrideAtCompileTime != Eigen::Dynamic &&
|
484 |
+
std::is_default_constructible<S>::value>;
|
485 |
+
// Otherwise, if there is a two-index constructor, assume it is (outer,inner) like
|
486 |
+
// Eigen::Stride, and use it:
|
487 |
+
template <typename S> using stride_ctor_dual = bool_constant<
|
488 |
+
!stride_ctor_default<S>::value && std::is_constructible<S, EigenIndex, EigenIndex>::value>;
|
489 |
+
// Otherwise, if there is a one-index constructor, and just one of the strides is dynamic, use
|
490 |
+
// it (passing whichever stride is dynamic).
|
491 |
+
template <typename S> using stride_ctor_outer = bool_constant<
|
492 |
+
!any_of<stride_ctor_default<S>, stride_ctor_dual<S>>::value &&
|
493 |
+
S::OuterStrideAtCompileTime == Eigen::Dynamic && S::InnerStrideAtCompileTime != Eigen::Dynamic &&
|
494 |
+
std::is_constructible<S, EigenIndex>::value>;
|
495 |
+
template <typename S> using stride_ctor_inner = bool_constant<
|
496 |
+
!any_of<stride_ctor_default<S>, stride_ctor_dual<S>>::value &&
|
497 |
+
S::InnerStrideAtCompileTime == Eigen::Dynamic && S::OuterStrideAtCompileTime != Eigen::Dynamic &&
|
498 |
+
std::is_constructible<S, EigenIndex>::value>;
|
499 |
+
|
500 |
+
template <typename S = StrideType, enable_if_t<stride_ctor_default<S>::value, int> = 0>
|
501 |
+
static S make_stride(EigenIndex, EigenIndex) { return S(); }
|
502 |
+
template <typename S = StrideType, enable_if_t<stride_ctor_dual<S>::value, int> = 0>
|
503 |
+
static S make_stride(EigenIndex outer, EigenIndex inner) { return S(outer, inner); }
|
504 |
+
template <typename S = StrideType, enable_if_t<stride_ctor_outer<S>::value, int> = 0>
|
505 |
+
static S make_stride(EigenIndex outer, EigenIndex) { return S(outer); }
|
506 |
+
template <typename S = StrideType, enable_if_t<stride_ctor_inner<S>::value, int> = 0>
|
507 |
+
static S make_stride(EigenIndex, EigenIndex inner) { return S(inner); }
|
508 |
+
|
509 |
+
};
|
510 |
+
|
511 |
+
// type_caster for special matrix types (e.g. DiagonalMatrix), which are EigenBase, but not
|
512 |
+
// EigenDense (i.e. they don't have a data(), at least not with the usual matrix layout).
|
513 |
+
// load() is not supported, but we can cast them into the python domain by first copying to a
|
514 |
+
// regular Eigen::Matrix, then casting that.
|
515 |
+
template <typename Type>
|
516 |
+
struct type_caster<Type, enable_if_t<is_eigen_other<Type>::value>> {
|
517 |
+
protected:
|
518 |
+
using Matrix = Eigen::Matrix<typename Type::Scalar, Type::RowsAtCompileTime, Type::ColsAtCompileTime>;
|
519 |
+
using props = EigenProps<Matrix>;
|
520 |
+
public:
|
521 |
+
static handle cast(const Type &src, return_value_policy /* policy */, handle /* parent */) {
|
522 |
+
handle h = eigen_encapsulate<props>(new Matrix(src));
|
523 |
+
return h;
|
524 |
+
}
|
525 |
+
static handle cast(const Type *src, return_value_policy policy, handle parent) { return cast(*src, policy, parent); }
|
526 |
+
|
527 |
+
static constexpr auto name = props::descriptor;
|
528 |
+
|
529 |
+
// Explicitly delete these: support python -> C++ conversion on these (i.e. these can be return
|
530 |
+
// types but not bound arguments). We still provide them (with an explicitly delete) so that
|
531 |
+
// you end up here if you try anyway.
|
532 |
+
bool load(handle, bool) = delete;
|
533 |
+
operator Type() = delete;
|
534 |
+
template <typename> using cast_op_type = Type;
|
535 |
+
};
|
536 |
+
|
537 |
+
template<typename Type>
|
538 |
+
struct type_caster<Type, enable_if_t<is_eigen_sparse<Type>::value>> {
|
539 |
+
using Scalar = typename Type::Scalar;
|
540 |
+
using StorageIndex = remove_reference_t<decltype(*std::declval<Type>().outerIndexPtr())>;
|
541 |
+
using Index = typename Type::Index;
|
542 |
+
static constexpr bool rowMajor = Type::IsRowMajor;
|
543 |
+
|
544 |
+
bool load(handle src, bool) {
|
545 |
+
if (!src)
|
546 |
+
return false;
|
547 |
+
|
548 |
+
auto obj = reinterpret_borrow<object>(src);
|
549 |
+
object sparse_module = module_::import("scipy.sparse");
|
550 |
+
object matrix_type = sparse_module.attr(
|
551 |
+
rowMajor ? "csr_matrix" : "csc_matrix");
|
552 |
+
|
553 |
+
if (!type::handle_of(obj).is(matrix_type)) {
|
554 |
+
try {
|
555 |
+
obj = matrix_type(obj);
|
556 |
+
} catch (const error_already_set &) {
|
557 |
+
return false;
|
558 |
+
}
|
559 |
+
}
|
560 |
+
|
561 |
+
auto values = array_t<Scalar>((object) obj.attr("data"));
|
562 |
+
auto innerIndices = array_t<StorageIndex>((object) obj.attr("indices"));
|
563 |
+
auto outerIndices = array_t<StorageIndex>((object) obj.attr("indptr"));
|
564 |
+
auto shape = pybind11::tuple((pybind11::object) obj.attr("shape"));
|
565 |
+
auto nnz = obj.attr("nnz").cast<Index>();
|
566 |
+
|
567 |
+
if (!values || !innerIndices || !outerIndices)
|
568 |
+
return false;
|
569 |
+
|
570 |
+
value = Eigen::MappedSparseMatrix<Scalar, Type::Flags, StorageIndex>(
|
571 |
+
shape[0].cast<Index>(), shape[1].cast<Index>(), nnz,
|
572 |
+
outerIndices.mutable_data(), innerIndices.mutable_data(), values.mutable_data());
|
573 |
+
|
574 |
+
return true;
|
575 |
+
}
|
576 |
+
|
577 |
+
static handle cast(const Type &src, return_value_policy /* policy */, handle /* parent */) {
|
578 |
+
const_cast<Type&>(src).makeCompressed();
|
579 |
+
|
580 |
+
object matrix_type = module_::import("scipy.sparse").attr(
|
581 |
+
rowMajor ? "csr_matrix" : "csc_matrix");
|
582 |
+
|
583 |
+
array data(src.nonZeros(), src.valuePtr());
|
584 |
+
array outerIndices((rowMajor ? src.rows() : src.cols()) + 1, src.outerIndexPtr());
|
585 |
+
array innerIndices(src.nonZeros(), src.innerIndexPtr());
|
586 |
+
|
587 |
+
return matrix_type(
|
588 |
+
std::make_tuple(data, innerIndices, outerIndices),
|
589 |
+
std::make_pair(src.rows(), src.cols())
|
590 |
+
).release();
|
591 |
+
}
|
592 |
+
|
593 |
+
PYBIND11_TYPE_CASTER(Type, _<(Type::IsRowMajor) != 0>("scipy.sparse.csr_matrix[", "scipy.sparse.csc_matrix[")
|
594 |
+
+ npy_format_descriptor<Scalar>::name + _("]"));
|
595 |
+
};
|
596 |
+
|
597 |
+
PYBIND11_NAMESPACE_END(detail)
|
598 |
+
PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)
|
599 |
+
|
600 |
+
#if defined(__GNUG__) || defined(__clang__)
|
601 |
+
# pragma GCC diagnostic pop
|
602 |
+
#elif defined(_MSC_VER)
|
603 |
+
# pragma warning(pop)
|
604 |
+
#endif
|
third-party/DPVO/Pangolin/components/pango_python/pybind11/include/pybind11/embed.h
ADDED
@@ -0,0 +1,201 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/*
|
2 |
+
pybind11/embed.h: Support for embedding the interpreter
|
3 |
+
|
4 |
+
Copyright (c) 2017 Wenzel Jakob <[email protected]>
|
5 |
+
|
6 |
+
All rights reserved. Use of this source code is governed by a
|
7 |
+
BSD-style license that can be found in the LICENSE file.
|
8 |
+
*/
|
9 |
+
|
10 |
+
#pragma once
|
11 |
+
|
12 |
+
#include "pybind11.h"
|
13 |
+
#include "eval.h"
|
14 |
+
|
15 |
+
#if defined(PYPY_VERSION)
|
16 |
+
# error Embedding the interpreter is not supported with PyPy
|
17 |
+
#endif
|
18 |
+
|
19 |
+
#if PY_MAJOR_VERSION >= 3
|
20 |
+
# define PYBIND11_EMBEDDED_MODULE_IMPL(name) \
|
21 |
+
extern "C" PyObject *pybind11_init_impl_##name(); \
|
22 |
+
extern "C" PyObject *pybind11_init_impl_##name() { \
|
23 |
+
return pybind11_init_wrapper_##name(); \
|
24 |
+
}
|
25 |
+
#else
|
26 |
+
# define PYBIND11_EMBEDDED_MODULE_IMPL(name) \
|
27 |
+
extern "C" void pybind11_init_impl_##name(); \
|
28 |
+
extern "C" void pybind11_init_impl_##name() { \
|
29 |
+
pybind11_init_wrapper_##name(); \
|
30 |
+
}
|
31 |
+
#endif
|
32 |
+
|
33 |
+
/** \rst
|
34 |
+
Add a new module to the table of builtins for the interpreter. Must be
|
35 |
+
defined in global scope. The first macro parameter is the name of the
|
36 |
+
module (without quotes). The second parameter is the variable which will
|
37 |
+
be used as the interface to add functions and classes to the module.
|
38 |
+
|
39 |
+
.. code-block:: cpp
|
40 |
+
|
41 |
+
PYBIND11_EMBEDDED_MODULE(example, m) {
|
42 |
+
// ... initialize functions and classes here
|
43 |
+
m.def("foo", []() {
|
44 |
+
return "Hello, World!";
|
45 |
+
});
|
46 |
+
}
|
47 |
+
\endrst */
|
48 |
+
#define PYBIND11_EMBEDDED_MODULE(name, variable) \
|
49 |
+
static ::pybind11::module_::module_def \
|
50 |
+
PYBIND11_CONCAT(pybind11_module_def_, name); \
|
51 |
+
static void PYBIND11_CONCAT(pybind11_init_, name)(::pybind11::module_ &); \
|
52 |
+
static PyObject PYBIND11_CONCAT(*pybind11_init_wrapper_, name)() { \
|
53 |
+
auto m = ::pybind11::module_::create_extension_module( \
|
54 |
+
PYBIND11_TOSTRING(name), nullptr, \
|
55 |
+
&PYBIND11_CONCAT(pybind11_module_def_, name)); \
|
56 |
+
try { \
|
57 |
+
PYBIND11_CONCAT(pybind11_init_, name)(m); \
|
58 |
+
return m.ptr(); \
|
59 |
+
} PYBIND11_CATCH_INIT_EXCEPTIONS \
|
60 |
+
} \
|
61 |
+
PYBIND11_EMBEDDED_MODULE_IMPL(name) \
|
62 |
+
::pybind11::detail::embedded_module PYBIND11_CONCAT(pybind11_module_, name) \
|
63 |
+
(PYBIND11_TOSTRING(name), \
|
64 |
+
PYBIND11_CONCAT(pybind11_init_impl_, name)); \
|
65 |
+
void PYBIND11_CONCAT(pybind11_init_, name)(::pybind11::module_ &variable)
|
66 |
+
|
67 |
+
|
68 |
+
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
|
69 |
+
PYBIND11_NAMESPACE_BEGIN(detail)
|
70 |
+
|
71 |
+
/// Python 2.7/3.x compatible version of `PyImport_AppendInittab` and error checks.
|
72 |
+
struct embedded_module {
|
73 |
+
#if PY_MAJOR_VERSION >= 3
|
74 |
+
using init_t = PyObject *(*)();
|
75 |
+
#else
|
76 |
+
using init_t = void (*)();
|
77 |
+
#endif
|
78 |
+
embedded_module(const char *name, init_t init) {
|
79 |
+
if (Py_IsInitialized() != 0)
|
80 |
+
pybind11_fail("Can't add new modules after the interpreter has been initialized");
|
81 |
+
|
82 |
+
auto result = PyImport_AppendInittab(name, init);
|
83 |
+
if (result == -1)
|
84 |
+
pybind11_fail("Insufficient memory to add a new module");
|
85 |
+
}
|
86 |
+
};
|
87 |
+
|
88 |
+
PYBIND11_NAMESPACE_END(detail)
|
89 |
+
|
90 |
+
/** \rst
|
91 |
+
Initialize the Python interpreter. No other pybind11 or CPython API functions can be
|
92 |
+
called before this is done; with the exception of `PYBIND11_EMBEDDED_MODULE`. The
|
93 |
+
optional parameter can be used to skip the registration of signal handlers (see the
|
94 |
+
`Python documentation`_ for details). Calling this function again after the interpreter
|
95 |
+
has already been initialized is a fatal error.
|
96 |
+
|
97 |
+
If initializing the Python interpreter fails, then the program is terminated. (This
|
98 |
+
is controlled by the CPython runtime and is an exception to pybind11's normal behavior
|
99 |
+
of throwing exceptions on errors.)
|
100 |
+
|
101 |
+
.. _Python documentation: https://docs.python.org/3/c-api/init.html#c.Py_InitializeEx
|
102 |
+
\endrst */
|
103 |
+
inline void initialize_interpreter(bool init_signal_handlers = true) {
|
104 |
+
if (Py_IsInitialized() != 0)
|
105 |
+
pybind11_fail("The interpreter is already running");
|
106 |
+
|
107 |
+
Py_InitializeEx(init_signal_handlers ? 1 : 0);
|
108 |
+
|
109 |
+
// Make .py files in the working directory available by default
|
110 |
+
module_::import("sys").attr("path").cast<list>().append(".");
|
111 |
+
}
|
112 |
+
|
113 |
+
/** \rst
|
114 |
+
Shut down the Python interpreter. No pybind11 or CPython API functions can be called
|
115 |
+
after this. In addition, pybind11 objects must not outlive the interpreter:
|
116 |
+
|
117 |
+
.. code-block:: cpp
|
118 |
+
|
119 |
+
{ // BAD
|
120 |
+
py::initialize_interpreter();
|
121 |
+
auto hello = py::str("Hello, World!");
|
122 |
+
py::finalize_interpreter();
|
123 |
+
} // <-- BOOM, hello's destructor is called after interpreter shutdown
|
124 |
+
|
125 |
+
{ // GOOD
|
126 |
+
py::initialize_interpreter();
|
127 |
+
{ // scoped
|
128 |
+
auto hello = py::str("Hello, World!");
|
129 |
+
} // <-- OK, hello is cleaned up properly
|
130 |
+
py::finalize_interpreter();
|
131 |
+
}
|
132 |
+
|
133 |
+
{ // BETTER
|
134 |
+
py::scoped_interpreter guard{};
|
135 |
+
auto hello = py::str("Hello, World!");
|
136 |
+
}
|
137 |
+
|
138 |
+
.. warning::
|
139 |
+
|
140 |
+
The interpreter can be restarted by calling `initialize_interpreter` again.
|
141 |
+
Modules created using pybind11 can be safely re-initialized. However, Python
|
142 |
+
itself cannot completely unload binary extension modules and there are several
|
143 |
+
caveats with regard to interpreter restarting. All the details can be found
|
144 |
+
in the CPython documentation. In short, not all interpreter memory may be
|
145 |
+
freed, either due to reference cycles or user-created global data.
|
146 |
+
|
147 |
+
\endrst */
|
148 |
+
inline void finalize_interpreter() {
|
149 |
+
handle builtins(PyEval_GetBuiltins());
|
150 |
+
const char *id = PYBIND11_INTERNALS_ID;
|
151 |
+
|
152 |
+
// Get the internals pointer (without creating it if it doesn't exist). It's possible for the
|
153 |
+
// internals to be created during Py_Finalize() (e.g. if a py::capsule calls `get_internals()`
|
154 |
+
// during destruction), so we get the pointer-pointer here and check it after Py_Finalize().
|
155 |
+
detail::internals **internals_ptr_ptr = detail::get_internals_pp();
|
156 |
+
// It could also be stashed in builtins, so look there too:
|
157 |
+
if (builtins.contains(id) && isinstance<capsule>(builtins[id]))
|
158 |
+
internals_ptr_ptr = capsule(builtins[id]);
|
159 |
+
|
160 |
+
Py_Finalize();
|
161 |
+
|
162 |
+
if (internals_ptr_ptr) {
|
163 |
+
delete *internals_ptr_ptr;
|
164 |
+
*internals_ptr_ptr = nullptr;
|
165 |
+
}
|
166 |
+
}
|
167 |
+
|
168 |
+
/** \rst
|
169 |
+
Scope guard version of `initialize_interpreter` and `finalize_interpreter`.
|
170 |
+
This a move-only guard and only a single instance can exist.
|
171 |
+
|
172 |
+
.. code-block:: cpp
|
173 |
+
|
174 |
+
#include <pybind11/embed.h>
|
175 |
+
|
176 |
+
int main() {
|
177 |
+
py::scoped_interpreter guard{};
|
178 |
+
py::print(Hello, World!);
|
179 |
+
} // <-- interpreter shutdown
|
180 |
+
\endrst */
|
181 |
+
class scoped_interpreter {
|
182 |
+
public:
|
183 |
+
scoped_interpreter(bool init_signal_handlers = true) {
|
184 |
+
initialize_interpreter(init_signal_handlers);
|
185 |
+
}
|
186 |
+
|
187 |
+
scoped_interpreter(const scoped_interpreter &) = delete;
|
188 |
+
scoped_interpreter(scoped_interpreter &&other) noexcept { other.is_valid = false; }
|
189 |
+
scoped_interpreter &operator=(const scoped_interpreter &) = delete;
|
190 |
+
scoped_interpreter &operator=(scoped_interpreter &&) = delete;
|
191 |
+
|
192 |
+
~scoped_interpreter() {
|
193 |
+
if (is_valid)
|
194 |
+
finalize_interpreter();
|
195 |
+
}
|
196 |
+
|
197 |
+
private:
|
198 |
+
bool is_valid = true;
|
199 |
+
};
|
200 |
+
|
201 |
+
PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)
|
third-party/DPVO/Pangolin/components/pango_python/pybind11/include/pybind11/eval.h
ADDED
@@ -0,0 +1,154 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/*
|
2 |
+
pybind11/exec.h: Support for evaluating Python expressions and statements
|
3 |
+
from strings and files
|
4 |
+
|
5 |
+
Copyright (c) 2016 Klemens Morgenstern <[email protected]> and
|
6 |
+
Wenzel Jakob <[email protected]>
|
7 |
+
|
8 |
+
All rights reserved. Use of this source code is governed by a
|
9 |
+
BSD-style license that can be found in the LICENSE file.
|
10 |
+
*/
|
11 |
+
|
12 |
+
#pragma once
|
13 |
+
|
14 |
+
#include <utility>
|
15 |
+
|
16 |
+
#include "pybind11.h"
|
17 |
+
|
18 |
+
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
|
19 |
+
PYBIND11_NAMESPACE_BEGIN(detail)
|
20 |
+
|
21 |
+
inline void ensure_builtins_in_globals(object &global) {
|
22 |
+
#if PY_VERSION_HEX < 0x03080000
|
23 |
+
// Running exec and eval on Python 2 and 3 adds `builtins` module under
|
24 |
+
// `__builtins__` key to globals if not yet present.
|
25 |
+
// Python 3.8 made PyRun_String behave similarly. Let's also do that for
|
26 |
+
// older versions, for consistency.
|
27 |
+
if (!global.contains("__builtins__"))
|
28 |
+
global["__builtins__"] = module_::import(PYBIND11_BUILTINS_MODULE);
|
29 |
+
#else
|
30 |
+
(void) global;
|
31 |
+
#endif
|
32 |
+
}
|
33 |
+
|
34 |
+
PYBIND11_NAMESPACE_END(detail)
|
35 |
+
|
36 |
+
enum eval_mode {
|
37 |
+
/// Evaluate a string containing an isolated expression
|
38 |
+
eval_expr,
|
39 |
+
|
40 |
+
/// Evaluate a string containing a single statement. Returns \c none
|
41 |
+
eval_single_statement,
|
42 |
+
|
43 |
+
/// Evaluate a string containing a sequence of statement. Returns \c none
|
44 |
+
eval_statements
|
45 |
+
};
|
46 |
+
|
47 |
+
template <eval_mode mode = eval_expr>
|
48 |
+
object eval(const str &expr, object global = globals(), object local = object()) {
|
49 |
+
if (!local)
|
50 |
+
local = global;
|
51 |
+
|
52 |
+
detail::ensure_builtins_in_globals(global);
|
53 |
+
|
54 |
+
/* PyRun_String does not accept a PyObject / encoding specifier,
|
55 |
+
this seems to be the only alternative */
|
56 |
+
std::string buffer = "# -*- coding: utf-8 -*-\n" + (std::string) expr;
|
57 |
+
|
58 |
+
int start = 0;
|
59 |
+
switch (mode) {
|
60 |
+
case eval_expr: start = Py_eval_input; break;
|
61 |
+
case eval_single_statement: start = Py_single_input; break;
|
62 |
+
case eval_statements: start = Py_file_input; break;
|
63 |
+
default: pybind11_fail("invalid evaluation mode");
|
64 |
+
}
|
65 |
+
|
66 |
+
PyObject *result = PyRun_String(buffer.c_str(), start, global.ptr(), local.ptr());
|
67 |
+
if (!result)
|
68 |
+
throw error_already_set();
|
69 |
+
return reinterpret_steal<object>(result);
|
70 |
+
}
|
71 |
+
|
72 |
+
template <eval_mode mode = eval_expr, size_t N>
|
73 |
+
object eval(const char (&s)[N], object global = globals(), object local = object()) {
|
74 |
+
/* Support raw string literals by removing common leading whitespace */
|
75 |
+
auto expr = (s[0] == '\n') ? str(module_::import("textwrap").attr("dedent")(s))
|
76 |
+
: str(s);
|
77 |
+
return eval<mode>(expr, global, local);
|
78 |
+
}
|
79 |
+
|
80 |
+
inline void exec(const str &expr, object global = globals(), object local = object()) {
|
81 |
+
eval<eval_statements>(expr, std::move(global), std::move(local));
|
82 |
+
}
|
83 |
+
|
84 |
+
template <size_t N>
|
85 |
+
void exec(const char (&s)[N], object global = globals(), object local = object()) {
|
86 |
+
eval<eval_statements>(s, global, local);
|
87 |
+
}
|
88 |
+
|
89 |
+
#if defined(PYPY_VERSION) && PY_VERSION_HEX >= 0x03000000
|
90 |
+
template <eval_mode mode = eval_statements>
|
91 |
+
object eval_file(str, object, object) {
|
92 |
+
pybind11_fail("eval_file not supported in PyPy3. Use eval");
|
93 |
+
}
|
94 |
+
template <eval_mode mode = eval_statements>
|
95 |
+
object eval_file(str, object) {
|
96 |
+
pybind11_fail("eval_file not supported in PyPy3. Use eval");
|
97 |
+
}
|
98 |
+
template <eval_mode mode = eval_statements>
|
99 |
+
object eval_file(str) {
|
100 |
+
pybind11_fail("eval_file not supported in PyPy3. Use eval");
|
101 |
+
}
|
102 |
+
#else
|
103 |
+
template <eval_mode mode = eval_statements>
|
104 |
+
object eval_file(str fname, object global = globals(), object local = object()) {
|
105 |
+
if (!local)
|
106 |
+
local = global;
|
107 |
+
|
108 |
+
detail::ensure_builtins_in_globals(global);
|
109 |
+
|
110 |
+
int start = 0;
|
111 |
+
switch (mode) {
|
112 |
+
case eval_expr: start = Py_eval_input; break;
|
113 |
+
case eval_single_statement: start = Py_single_input; break;
|
114 |
+
case eval_statements: start = Py_file_input; break;
|
115 |
+
default: pybind11_fail("invalid evaluation mode");
|
116 |
+
}
|
117 |
+
|
118 |
+
int closeFile = 1;
|
119 |
+
std::string fname_str = (std::string) fname;
|
120 |
+
#if PY_VERSION_HEX >= 0x03040000
|
121 |
+
FILE *f = _Py_fopen_obj(fname.ptr(), "r");
|
122 |
+
#elif PY_VERSION_HEX >= 0x03000000
|
123 |
+
FILE *f = _Py_fopen(fname.ptr(), "r");
|
124 |
+
#else
|
125 |
+
/* No unicode support in open() :( */
|
126 |
+
auto fobj = reinterpret_steal<object>(PyFile_FromString(
|
127 |
+
const_cast<char *>(fname_str.c_str()),
|
128 |
+
const_cast<char*>("r")));
|
129 |
+
FILE *f = nullptr;
|
130 |
+
if (fobj)
|
131 |
+
f = PyFile_AsFile(fobj.ptr());
|
132 |
+
closeFile = 0;
|
133 |
+
#endif
|
134 |
+
if (!f) {
|
135 |
+
PyErr_Clear();
|
136 |
+
pybind11_fail("File \"" + fname_str + "\" could not be opened!");
|
137 |
+
}
|
138 |
+
|
139 |
+
#if PY_VERSION_HEX < 0x03000000 && defined(PYPY_VERSION)
|
140 |
+
PyObject *result = PyRun_File(f, fname_str.c_str(), start, global.ptr(),
|
141 |
+
local.ptr());
|
142 |
+
(void) closeFile;
|
143 |
+
#else
|
144 |
+
PyObject *result = PyRun_FileEx(f, fname_str.c_str(), start, global.ptr(),
|
145 |
+
local.ptr(), closeFile);
|
146 |
+
#endif
|
147 |
+
|
148 |
+
if (!result)
|
149 |
+
throw error_already_set();
|
150 |
+
return reinterpret_steal<object>(result);
|
151 |
+
}
|
152 |
+
#endif
|
153 |
+
|
154 |
+
PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)
|
third-party/DPVO/Pangolin/components/pango_python/pybind11/include/pybind11/functional.h
ADDED
@@ -0,0 +1,117 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/*
|
2 |
+
pybind11/functional.h: std::function<> support
|
3 |
+
|
4 |
+
Copyright (c) 2016 Wenzel Jakob <[email protected]>
|
5 |
+
|
6 |
+
All rights reserved. Use of this source code is governed by a
|
7 |
+
BSD-style license that can be found in the LICENSE file.
|
8 |
+
*/
|
9 |
+
|
10 |
+
#pragma once
|
11 |
+
|
12 |
+
#include "pybind11.h"
|
13 |
+
#include <functional>
|
14 |
+
|
15 |
+
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
|
16 |
+
PYBIND11_NAMESPACE_BEGIN(detail)
|
17 |
+
|
18 |
+
template <typename Return, typename... Args>
|
19 |
+
struct type_caster<std::function<Return(Args...)>> {
|
20 |
+
using type = std::function<Return(Args...)>;
|
21 |
+
using retval_type = conditional_t<std::is_same<Return, void>::value, void_type, Return>;
|
22 |
+
using function_type = Return (*) (Args...);
|
23 |
+
|
24 |
+
public:
|
25 |
+
bool load(handle src, bool convert) {
|
26 |
+
if (src.is_none()) {
|
27 |
+
// Defer accepting None to other overloads (if we aren't in convert mode):
|
28 |
+
if (!convert) return false;
|
29 |
+
return true;
|
30 |
+
}
|
31 |
+
|
32 |
+
if (!isinstance<function>(src))
|
33 |
+
return false;
|
34 |
+
|
35 |
+
auto func = reinterpret_borrow<function>(src);
|
36 |
+
|
37 |
+
/*
|
38 |
+
When passing a C++ function as an argument to another C++
|
39 |
+
function via Python, every function call would normally involve
|
40 |
+
a full C++ -> Python -> C++ roundtrip, which can be prohibitive.
|
41 |
+
Here, we try to at least detect the case where the function is
|
42 |
+
stateless (i.e. function pointer or lambda function without
|
43 |
+
captured variables), in which case the roundtrip can be avoided.
|
44 |
+
*/
|
45 |
+
if (auto cfunc = func.cpp_function()) {
|
46 |
+
auto cfunc_self = PyCFunction_GET_SELF(cfunc.ptr());
|
47 |
+
if (isinstance<capsule>(cfunc_self)) {
|
48 |
+
auto c = reinterpret_borrow<capsule>(cfunc_self);
|
49 |
+
auto rec = (function_record *) c;
|
50 |
+
|
51 |
+
while (rec != nullptr) {
|
52 |
+
if (rec->is_stateless
|
53 |
+
&& same_type(typeid(function_type),
|
54 |
+
*reinterpret_cast<const std::type_info *>(rec->data[1]))) {
|
55 |
+
struct capture {
|
56 |
+
function_type f;
|
57 |
+
};
|
58 |
+
value = ((capture *) &rec->data)->f;
|
59 |
+
return true;
|
60 |
+
}
|
61 |
+
rec = rec->next;
|
62 |
+
}
|
63 |
+
}
|
64 |
+
// PYPY segfaults here when passing builtin function like sum.
|
65 |
+
// Raising an fail exception here works to prevent the segfault, but only on gcc.
|
66 |
+
// See PR #1413 for full details
|
67 |
+
}
|
68 |
+
|
69 |
+
// ensure GIL is held during functor destruction
|
70 |
+
struct func_handle {
|
71 |
+
function f;
|
72 |
+
func_handle(function &&f_) noexcept : f(std::move(f_)) {}
|
73 |
+
func_handle(const func_handle &f_) { operator=(f_); }
|
74 |
+
func_handle &operator=(const func_handle &f_) {
|
75 |
+
gil_scoped_acquire acq;
|
76 |
+
f = f_.f;
|
77 |
+
return *this;
|
78 |
+
}
|
79 |
+
~func_handle() {
|
80 |
+
gil_scoped_acquire acq;
|
81 |
+
function kill_f(std::move(f));
|
82 |
+
}
|
83 |
+
};
|
84 |
+
|
85 |
+
// to emulate 'move initialization capture' in C++11
|
86 |
+
struct func_wrapper {
|
87 |
+
func_handle hfunc;
|
88 |
+
func_wrapper(func_handle &&hf) noexcept : hfunc(std::move(hf)) {}
|
89 |
+
Return operator()(Args... args) const {
|
90 |
+
gil_scoped_acquire acq;
|
91 |
+
object retval(hfunc.f(std::forward<Args>(args)...));
|
92 |
+
/* Visual studio 2015 parser issue: need parentheses around this expression */
|
93 |
+
return (retval.template cast<Return>());
|
94 |
+
}
|
95 |
+
};
|
96 |
+
|
97 |
+
value = func_wrapper(func_handle(std::move(func)));
|
98 |
+
return true;
|
99 |
+
}
|
100 |
+
|
101 |
+
template <typename Func>
|
102 |
+
static handle cast(Func &&f_, return_value_policy policy, handle /* parent */) {
|
103 |
+
if (!f_)
|
104 |
+
return none().inc_ref();
|
105 |
+
|
106 |
+
auto result = f_.template target<function_type>();
|
107 |
+
if (result)
|
108 |
+
return cpp_function(*result, policy).release();
|
109 |
+
return cpp_function(std::forward<Func>(f_), policy).release();
|
110 |
+
}
|
111 |
+
|
112 |
+
PYBIND11_TYPE_CASTER(type, _("Callable[[") + concat(make_caster<Args>::name...) + _("], ")
|
113 |
+
+ make_caster<retval_type>::name + _("]"));
|
114 |
+
};
|
115 |
+
|
116 |
+
PYBIND11_NAMESPACE_END(detail)
|
117 |
+
PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)
|
third-party/DPVO/Pangolin/components/pango_python/pybind11/include/pybind11/gil.h
ADDED
@@ -0,0 +1,193 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/*
|
2 |
+
pybind11/gil.h: RAII helpers for managing the GIL
|
3 |
+
|
4 |
+
Copyright (c) 2016 Wenzel Jakob <[email protected]>
|
5 |
+
|
6 |
+
All rights reserved. Use of this source code is governed by a
|
7 |
+
BSD-style license that can be found in the LICENSE file.
|
8 |
+
*/
|
9 |
+
|
10 |
+
#pragma once
|
11 |
+
|
12 |
+
#include "detail/common.h"
|
13 |
+
#include "detail/internals.h"
|
14 |
+
|
15 |
+
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
|
16 |
+
|
17 |
+
|
18 |
+
PYBIND11_NAMESPACE_BEGIN(detail)
|
19 |
+
|
20 |
+
// forward declarations
|
21 |
+
PyThreadState *get_thread_state_unchecked();
|
22 |
+
|
23 |
+
PYBIND11_NAMESPACE_END(detail)
|
24 |
+
|
25 |
+
|
26 |
+
#if defined(WITH_THREAD) && !defined(PYPY_VERSION)
|
27 |
+
|
28 |
+
/* The functions below essentially reproduce the PyGILState_* API using a RAII
|
29 |
+
* pattern, but there are a few important differences:
|
30 |
+
*
|
31 |
+
* 1. When acquiring the GIL from an non-main thread during the finalization
|
32 |
+
* phase, the GILState API blindly terminates the calling thread, which
|
33 |
+
* is often not what is wanted. This API does not do this.
|
34 |
+
*
|
35 |
+
* 2. The gil_scoped_release function can optionally cut the relationship
|
36 |
+
* of a PyThreadState and its associated thread, which allows moving it to
|
37 |
+
* another thread (this is a fairly rare/advanced use case).
|
38 |
+
*
|
39 |
+
* 3. The reference count of an acquired thread state can be controlled. This
|
40 |
+
* can be handy to prevent cases where callbacks issued from an external
|
41 |
+
* thread would otherwise constantly construct and destroy thread state data
|
42 |
+
* structures.
|
43 |
+
*
|
44 |
+
* See the Python bindings of NanoGUI (http://github.com/wjakob/nanogui) for an
|
45 |
+
* example which uses features 2 and 3 to migrate the Python thread of
|
46 |
+
* execution to another thread (to run the event loop on the original thread,
|
47 |
+
* in this case).
|
48 |
+
*/
|
49 |
+
|
50 |
+
class gil_scoped_acquire {
|
51 |
+
public:
|
52 |
+
PYBIND11_NOINLINE gil_scoped_acquire() {
|
53 |
+
auto const &internals = detail::get_internals();
|
54 |
+
tstate = (PyThreadState *) PYBIND11_TLS_GET_VALUE(internals.tstate);
|
55 |
+
|
56 |
+
if (!tstate) {
|
57 |
+
/* Check if the GIL was acquired using the PyGILState_* API instead (e.g. if
|
58 |
+
calling from a Python thread). Since we use a different key, this ensures
|
59 |
+
we don't create a new thread state and deadlock in PyEval_AcquireThread
|
60 |
+
below. Note we don't save this state with internals.tstate, since we don't
|
61 |
+
create it we would fail to clear it (its reference count should be > 0). */
|
62 |
+
tstate = PyGILState_GetThisThreadState();
|
63 |
+
}
|
64 |
+
|
65 |
+
if (!tstate) {
|
66 |
+
tstate = PyThreadState_New(internals.istate);
|
67 |
+
#if !defined(NDEBUG)
|
68 |
+
if (!tstate)
|
69 |
+
pybind11_fail("scoped_acquire: could not create thread state!");
|
70 |
+
#endif
|
71 |
+
tstate->gilstate_counter = 0;
|
72 |
+
PYBIND11_TLS_REPLACE_VALUE(internals.tstate, tstate);
|
73 |
+
} else {
|
74 |
+
release = detail::get_thread_state_unchecked() != tstate;
|
75 |
+
}
|
76 |
+
|
77 |
+
if (release) {
|
78 |
+
PyEval_AcquireThread(tstate);
|
79 |
+
}
|
80 |
+
|
81 |
+
inc_ref();
|
82 |
+
}
|
83 |
+
|
84 |
+
void inc_ref() {
|
85 |
+
++tstate->gilstate_counter;
|
86 |
+
}
|
87 |
+
|
88 |
+
PYBIND11_NOINLINE void dec_ref() {
|
89 |
+
--tstate->gilstate_counter;
|
90 |
+
#if !defined(NDEBUG)
|
91 |
+
if (detail::get_thread_state_unchecked() != tstate)
|
92 |
+
pybind11_fail("scoped_acquire::dec_ref(): thread state must be current!");
|
93 |
+
if (tstate->gilstate_counter < 0)
|
94 |
+
pybind11_fail("scoped_acquire::dec_ref(): reference count underflow!");
|
95 |
+
#endif
|
96 |
+
if (tstate->gilstate_counter == 0) {
|
97 |
+
#if !defined(NDEBUG)
|
98 |
+
if (!release)
|
99 |
+
pybind11_fail("scoped_acquire::dec_ref(): internal error!");
|
100 |
+
#endif
|
101 |
+
PyThreadState_Clear(tstate);
|
102 |
+
if (active)
|
103 |
+
PyThreadState_DeleteCurrent();
|
104 |
+
PYBIND11_TLS_DELETE_VALUE(detail::get_internals().tstate);
|
105 |
+
release = false;
|
106 |
+
}
|
107 |
+
}
|
108 |
+
|
109 |
+
/// This method will disable the PyThreadState_DeleteCurrent call and the
|
110 |
+
/// GIL won't be acquired. This method should be used if the interpreter
|
111 |
+
/// could be shutting down when this is called, as thread deletion is not
|
112 |
+
/// allowed during shutdown. Check _Py_IsFinalizing() on Python 3.7+, and
|
113 |
+
/// protect subsequent code.
|
114 |
+
PYBIND11_NOINLINE void disarm() {
|
115 |
+
active = false;
|
116 |
+
}
|
117 |
+
|
118 |
+
PYBIND11_NOINLINE ~gil_scoped_acquire() {
|
119 |
+
dec_ref();
|
120 |
+
if (release)
|
121 |
+
PyEval_SaveThread();
|
122 |
+
}
|
123 |
+
private:
|
124 |
+
PyThreadState *tstate = nullptr;
|
125 |
+
bool release = true;
|
126 |
+
bool active = true;
|
127 |
+
};
|
128 |
+
|
129 |
+
class gil_scoped_release {
|
130 |
+
public:
|
131 |
+
explicit gil_scoped_release(bool disassoc = false) : disassoc(disassoc) {
|
132 |
+
// `get_internals()` must be called here unconditionally in order to initialize
|
133 |
+
// `internals.tstate` for subsequent `gil_scoped_acquire` calls. Otherwise, an
|
134 |
+
// initialization race could occur as multiple threads try `gil_scoped_acquire`.
|
135 |
+
const auto &internals = detail::get_internals();
|
136 |
+
tstate = PyEval_SaveThread();
|
137 |
+
if (disassoc) {
|
138 |
+
auto key = internals.tstate;
|
139 |
+
PYBIND11_TLS_DELETE_VALUE(key);
|
140 |
+
}
|
141 |
+
}
|
142 |
+
|
143 |
+
/// This method will disable the PyThreadState_DeleteCurrent call and the
|
144 |
+
/// GIL won't be acquired. This method should be used if the interpreter
|
145 |
+
/// could be shutting down when this is called, as thread deletion is not
|
146 |
+
/// allowed during shutdown. Check _Py_IsFinalizing() on Python 3.7+, and
|
147 |
+
/// protect subsequent code.
|
148 |
+
PYBIND11_NOINLINE void disarm() {
|
149 |
+
active = false;
|
150 |
+
}
|
151 |
+
|
152 |
+
~gil_scoped_release() {
|
153 |
+
if (!tstate)
|
154 |
+
return;
|
155 |
+
// `PyEval_RestoreThread()` should not be called if runtime is finalizing
|
156 |
+
if (active)
|
157 |
+
PyEval_RestoreThread(tstate);
|
158 |
+
if (disassoc) {
|
159 |
+
auto key = detail::get_internals().tstate;
|
160 |
+
PYBIND11_TLS_REPLACE_VALUE(key, tstate);
|
161 |
+
}
|
162 |
+
}
|
163 |
+
private:
|
164 |
+
PyThreadState *tstate;
|
165 |
+
bool disassoc;
|
166 |
+
bool active = true;
|
167 |
+
};
|
168 |
+
#elif defined(PYPY_VERSION)
|
169 |
+
class gil_scoped_acquire {
|
170 |
+
PyGILState_STATE state;
|
171 |
+
public:
|
172 |
+
gil_scoped_acquire() { state = PyGILState_Ensure(); }
|
173 |
+
~gil_scoped_acquire() { PyGILState_Release(state); }
|
174 |
+
void disarm() {}
|
175 |
+
};
|
176 |
+
|
177 |
+
class gil_scoped_release {
|
178 |
+
PyThreadState *state;
|
179 |
+
public:
|
180 |
+
gil_scoped_release() { state = PyEval_SaveThread(); }
|
181 |
+
~gil_scoped_release() { PyEval_RestoreThread(state); }
|
182 |
+
void disarm() {}
|
183 |
+
};
|
184 |
+
#else
|
185 |
+
class gil_scoped_acquire {
|
186 |
+
void disarm() {}
|
187 |
+
};
|
188 |
+
class gil_scoped_release {
|
189 |
+
void disarm() {}
|
190 |
+
};
|
191 |
+
#endif
|
192 |
+
|
193 |
+
PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)
|
third-party/DPVO/Pangolin/components/pango_python/pybind11/include/pybind11/iostream.h
ADDED
@@ -0,0 +1,273 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/*
|
2 |
+
pybind11/iostream.h -- Tools to assist with redirecting cout and cerr to Python
|
3 |
+
|
4 |
+
Copyright (c) 2017 Henry F. Schreiner
|
5 |
+
|
6 |
+
All rights reserved. Use of this source code is governed by a
|
7 |
+
BSD-style license that can be found in the LICENSE file.
|
8 |
+
|
9 |
+
WARNING: The implementation in this file is NOT thread safe. Multiple
|
10 |
+
threads writing to a redirected ostream concurrently cause data races
|
11 |
+
and potentially buffer overflows. Therefore it is currently a requirement
|
12 |
+
that all (possibly) concurrent redirected ostream writes are protected by
|
13 |
+
a mutex.
|
14 |
+
#HelpAppreciated: Work on iostream.h thread safety.
|
15 |
+
For more background see the discussions under
|
16 |
+
https://github.com/pybind/pybind11/pull/2982 and
|
17 |
+
https://github.com/pybind/pybind11/pull/2995.
|
18 |
+
*/
|
19 |
+
|
20 |
+
#pragma once
|
21 |
+
|
22 |
+
#include "pybind11.h"
|
23 |
+
|
24 |
+
#include <algorithm>
|
25 |
+
#include <cstring>
|
26 |
+
#include <iostream>
|
27 |
+
#include <iterator>
|
28 |
+
#include <memory>
|
29 |
+
#include <ostream>
|
30 |
+
#include <streambuf>
|
31 |
+
#include <string>
|
32 |
+
#include <utility>
|
33 |
+
|
34 |
+
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
|
35 |
+
PYBIND11_NAMESPACE_BEGIN(detail)
|
36 |
+
|
37 |
+
// Buffer that writes to Python instead of C++
|
38 |
+
class pythonbuf : public std::streambuf {
|
39 |
+
private:
|
40 |
+
using traits_type = std::streambuf::traits_type;
|
41 |
+
|
42 |
+
const size_t buf_size;
|
43 |
+
std::unique_ptr<char[]> d_buffer;
|
44 |
+
object pywrite;
|
45 |
+
object pyflush;
|
46 |
+
|
47 |
+
int overflow(int c) override {
|
48 |
+
if (!traits_type::eq_int_type(c, traits_type::eof())) {
|
49 |
+
*pptr() = traits_type::to_char_type(c);
|
50 |
+
pbump(1);
|
51 |
+
}
|
52 |
+
return sync() == 0 ? traits_type::not_eof(c) : traits_type::eof();
|
53 |
+
}
|
54 |
+
|
55 |
+
// Computes how many bytes at the end of the buffer are part of an
|
56 |
+
// incomplete sequence of UTF-8 bytes.
|
57 |
+
// Precondition: pbase() < pptr()
|
58 |
+
size_t utf8_remainder() const {
|
59 |
+
const auto rbase = std::reverse_iterator<char *>(pbase());
|
60 |
+
const auto rpptr = std::reverse_iterator<char *>(pptr());
|
61 |
+
auto is_ascii = [](char c) {
|
62 |
+
return (static_cast<unsigned char>(c) & 0x80) == 0x00;
|
63 |
+
};
|
64 |
+
auto is_leading = [](char c) {
|
65 |
+
return (static_cast<unsigned char>(c) & 0xC0) == 0xC0;
|
66 |
+
};
|
67 |
+
auto is_leading_2b = [](char c) {
|
68 |
+
return static_cast<unsigned char>(c) <= 0xDF;
|
69 |
+
};
|
70 |
+
auto is_leading_3b = [](char c) {
|
71 |
+
return static_cast<unsigned char>(c) <= 0xEF;
|
72 |
+
};
|
73 |
+
// If the last character is ASCII, there are no incomplete code points
|
74 |
+
if (is_ascii(*rpptr))
|
75 |
+
return 0;
|
76 |
+
// Otherwise, work back from the end of the buffer and find the first
|
77 |
+
// UTF-8 leading byte
|
78 |
+
const auto rpend = rbase - rpptr >= 3 ? rpptr + 3 : rbase;
|
79 |
+
const auto leading = std::find_if(rpptr, rpend, is_leading);
|
80 |
+
if (leading == rbase)
|
81 |
+
return 0;
|
82 |
+
const auto dist = static_cast<size_t>(leading - rpptr);
|
83 |
+
size_t remainder = 0;
|
84 |
+
|
85 |
+
if (dist == 0)
|
86 |
+
remainder = 1; // 1-byte code point is impossible
|
87 |
+
else if (dist == 1)
|
88 |
+
remainder = is_leading_2b(*leading) ? 0 : dist + 1;
|
89 |
+
else if (dist == 2)
|
90 |
+
remainder = is_leading_3b(*leading) ? 0 : dist + 1;
|
91 |
+
// else if (dist >= 3), at least 4 bytes before encountering an UTF-8
|
92 |
+
// leading byte, either no remainder or invalid UTF-8.
|
93 |
+
// Invalid UTF-8 will cause an exception later when converting
|
94 |
+
// to a Python string, so that's not handled here.
|
95 |
+
return remainder;
|
96 |
+
}
|
97 |
+
|
98 |
+
// This function must be non-virtual to be called in a destructor.
|
99 |
+
int _sync() {
|
100 |
+
if (pbase() != pptr()) { // If buffer is not empty
|
101 |
+
gil_scoped_acquire tmp;
|
102 |
+
// This subtraction cannot be negative, so dropping the sign.
|
103 |
+
auto size = static_cast<size_t>(pptr() - pbase());
|
104 |
+
size_t remainder = utf8_remainder();
|
105 |
+
|
106 |
+
if (size > remainder) {
|
107 |
+
str line(pbase(), size - remainder);
|
108 |
+
pywrite(line);
|
109 |
+
pyflush();
|
110 |
+
}
|
111 |
+
|
112 |
+
// Copy the remainder at the end of the buffer to the beginning:
|
113 |
+
if (remainder > 0)
|
114 |
+
std::memmove(pbase(), pptr() - remainder, remainder);
|
115 |
+
setp(pbase(), epptr());
|
116 |
+
pbump(static_cast<int>(remainder));
|
117 |
+
}
|
118 |
+
return 0;
|
119 |
+
}
|
120 |
+
|
121 |
+
int sync() override {
|
122 |
+
return _sync();
|
123 |
+
}
|
124 |
+
|
125 |
+
public:
|
126 |
+
pythonbuf(const object &pyostream, size_t buffer_size = 1024)
|
127 |
+
: buf_size(buffer_size), d_buffer(new char[buf_size]), pywrite(pyostream.attr("write")),
|
128 |
+
pyflush(pyostream.attr("flush")) {
|
129 |
+
setp(d_buffer.get(), d_buffer.get() + buf_size - 1);
|
130 |
+
}
|
131 |
+
|
132 |
+
pythonbuf(pythonbuf&&) = default;
|
133 |
+
|
134 |
+
/// Sync before destroy
|
135 |
+
~pythonbuf() override {
|
136 |
+
_sync();
|
137 |
+
}
|
138 |
+
};
|
139 |
+
|
140 |
+
PYBIND11_NAMESPACE_END(detail)
|
141 |
+
|
142 |
+
|
143 |
+
/** \rst
|
144 |
+
This a move-only guard that redirects output.
|
145 |
+
|
146 |
+
.. code-block:: cpp
|
147 |
+
|
148 |
+
#include <pybind11/iostream.h>
|
149 |
+
|
150 |
+
...
|
151 |
+
|
152 |
+
{
|
153 |
+
py::scoped_ostream_redirect output;
|
154 |
+
std::cout << "Hello, World!"; // Python stdout
|
155 |
+
} // <-- return std::cout to normal
|
156 |
+
|
157 |
+
You can explicitly pass the c++ stream and the python object,
|
158 |
+
for example to guard stderr instead.
|
159 |
+
|
160 |
+
.. code-block:: cpp
|
161 |
+
|
162 |
+
{
|
163 |
+
py::scoped_ostream_redirect output{std::cerr, py::module::import("sys").attr("stderr")};
|
164 |
+
std::cout << "Hello, World!";
|
165 |
+
}
|
166 |
+
\endrst */
|
167 |
+
class scoped_ostream_redirect {
|
168 |
+
protected:
|
169 |
+
std::streambuf *old;
|
170 |
+
std::ostream &costream;
|
171 |
+
detail::pythonbuf buffer;
|
172 |
+
|
173 |
+
public:
|
174 |
+
scoped_ostream_redirect(std::ostream &costream = std::cout,
|
175 |
+
const object &pyostream = module_::import("sys").attr("stdout"))
|
176 |
+
: costream(costream), buffer(pyostream) {
|
177 |
+
old = costream.rdbuf(&buffer);
|
178 |
+
}
|
179 |
+
|
180 |
+
~scoped_ostream_redirect() {
|
181 |
+
costream.rdbuf(old);
|
182 |
+
}
|
183 |
+
|
184 |
+
scoped_ostream_redirect(const scoped_ostream_redirect &) = delete;
|
185 |
+
scoped_ostream_redirect(scoped_ostream_redirect &&other) = default;
|
186 |
+
scoped_ostream_redirect &operator=(const scoped_ostream_redirect &) = delete;
|
187 |
+
scoped_ostream_redirect &operator=(scoped_ostream_redirect &&) = delete;
|
188 |
+
};
|
189 |
+
|
190 |
+
|
191 |
+
/** \rst
|
192 |
+
Like `scoped_ostream_redirect`, but redirects cerr by default. This class
|
193 |
+
is provided primary to make ``py::call_guard`` easier to make.
|
194 |
+
|
195 |
+
.. code-block:: cpp
|
196 |
+
|
197 |
+
m.def("noisy_func", &noisy_func,
|
198 |
+
py::call_guard<scoped_ostream_redirect,
|
199 |
+
scoped_estream_redirect>());
|
200 |
+
|
201 |
+
\endrst */
|
202 |
+
class scoped_estream_redirect : public scoped_ostream_redirect {
|
203 |
+
public:
|
204 |
+
scoped_estream_redirect(std::ostream &costream = std::cerr,
|
205 |
+
const object &pyostream = module_::import("sys").attr("stderr"))
|
206 |
+
: scoped_ostream_redirect(costream, pyostream) {}
|
207 |
+
};
|
208 |
+
|
209 |
+
|
210 |
+
PYBIND11_NAMESPACE_BEGIN(detail)
|
211 |
+
|
212 |
+
// Class to redirect output as a context manager. C++ backend.
|
213 |
+
class OstreamRedirect {
|
214 |
+
bool do_stdout_;
|
215 |
+
bool do_stderr_;
|
216 |
+
std::unique_ptr<scoped_ostream_redirect> redirect_stdout;
|
217 |
+
std::unique_ptr<scoped_estream_redirect> redirect_stderr;
|
218 |
+
|
219 |
+
public:
|
220 |
+
OstreamRedirect(bool do_stdout = true, bool do_stderr = true)
|
221 |
+
: do_stdout_(do_stdout), do_stderr_(do_stderr) {}
|
222 |
+
|
223 |
+
void enter() {
|
224 |
+
if (do_stdout_)
|
225 |
+
redirect_stdout.reset(new scoped_ostream_redirect());
|
226 |
+
if (do_stderr_)
|
227 |
+
redirect_stderr.reset(new scoped_estream_redirect());
|
228 |
+
}
|
229 |
+
|
230 |
+
void exit() {
|
231 |
+
redirect_stdout.reset();
|
232 |
+
redirect_stderr.reset();
|
233 |
+
}
|
234 |
+
};
|
235 |
+
|
236 |
+
PYBIND11_NAMESPACE_END(detail)
|
237 |
+
|
238 |
+
/** \rst
|
239 |
+
This is a helper function to add a C++ redirect context manager to Python
|
240 |
+
instead of using a C++ guard. To use it, add the following to your binding code:
|
241 |
+
|
242 |
+
.. code-block:: cpp
|
243 |
+
|
244 |
+
#include <pybind11/iostream.h>
|
245 |
+
|
246 |
+
...
|
247 |
+
|
248 |
+
py::add_ostream_redirect(m, "ostream_redirect");
|
249 |
+
|
250 |
+
You now have a Python context manager that redirects your output:
|
251 |
+
|
252 |
+
.. code-block:: python
|
253 |
+
|
254 |
+
with m.ostream_redirect():
|
255 |
+
m.print_to_cout_function()
|
256 |
+
|
257 |
+
This manager can optionally be told which streams to operate on:
|
258 |
+
|
259 |
+
.. code-block:: python
|
260 |
+
|
261 |
+
with m.ostream_redirect(stdout=true, stderr=true):
|
262 |
+
m.noisy_function_with_error_printing()
|
263 |
+
|
264 |
+
\endrst */
|
265 |
+
inline class_<detail::OstreamRedirect>
|
266 |
+
add_ostream_redirect(module_ m, const std::string &name = "ostream_redirect") {
|
267 |
+
return class_<detail::OstreamRedirect>(std::move(m), name.c_str(), module_local())
|
268 |
+
.def(init<bool, bool>(), arg("stdout") = true, arg("stderr") = true)
|
269 |
+
.def("__enter__", &detail::OstreamRedirect::enter)
|
270 |
+
.def("__exit__", [](detail::OstreamRedirect &self_, const args &) { self_.exit(); });
|
271 |
+
}
|
272 |
+
|
273 |
+
PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)
|
third-party/DPVO/Pangolin/components/pango_python/pybind11/include/pybind11/numpy.h
ADDED
@@ -0,0 +1,1708 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/*
|
2 |
+
pybind11/numpy.h: Basic NumPy support, vectorize() wrapper
|
3 |
+
|
4 |
+
Copyright (c) 2016 Wenzel Jakob <[email protected]>
|
5 |
+
|
6 |
+
All rights reserved. Use of this source code is governed by a
|
7 |
+
BSD-style license that can be found in the LICENSE file.
|
8 |
+
*/
|
9 |
+
|
10 |
+
#pragma once
|
11 |
+
|
12 |
+
#include "pybind11.h"
|
13 |
+
#include "complex.h"
|
14 |
+
#include <numeric>
|
15 |
+
#include <algorithm>
|
16 |
+
#include <array>
|
17 |
+
#include <cstdint>
|
18 |
+
#include <cstdlib>
|
19 |
+
#include <cstring>
|
20 |
+
#include <sstream>
|
21 |
+
#include <string>
|
22 |
+
#include <functional>
|
23 |
+
#include <type_traits>
|
24 |
+
#include <utility>
|
25 |
+
#include <vector>
|
26 |
+
#include <typeindex>
|
27 |
+
|
28 |
+
#if defined(_MSC_VER)
|
29 |
+
# pragma warning(push)
|
30 |
+
# pragma warning(disable: 4127) // warning C4127: Conditional expression is constant
|
31 |
+
#endif
|
32 |
+
|
33 |
+
/* This will be true on all flat address space platforms and allows us to reduce the
|
34 |
+
whole npy_intp / ssize_t / Py_intptr_t business down to just ssize_t for all size
|
35 |
+
and dimension types (e.g. shape, strides, indexing), instead of inflicting this
|
36 |
+
upon the library user. */
|
37 |
+
static_assert(sizeof(::pybind11::ssize_t) == sizeof(Py_intptr_t), "ssize_t != Py_intptr_t");
|
38 |
+
static_assert(std::is_signed<Py_intptr_t>::value, "Py_intptr_t must be signed");
|
39 |
+
// We now can reinterpret_cast between py::ssize_t and Py_intptr_t (MSVC + PyPy cares)
|
40 |
+
|
41 |
+
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
|
42 |
+
|
43 |
+
class array; // Forward declaration
|
44 |
+
|
45 |
+
PYBIND11_NAMESPACE_BEGIN(detail)
|
46 |
+
|
47 |
+
template <> struct handle_type_name<array> { static constexpr auto name = _("numpy.ndarray"); };
|
48 |
+
|
49 |
+
template <typename type, typename SFINAE = void> struct npy_format_descriptor;
|
50 |
+
|
51 |
+
struct PyArrayDescr_Proxy {
|
52 |
+
PyObject_HEAD
|
53 |
+
PyObject *typeobj;
|
54 |
+
char kind;
|
55 |
+
char type;
|
56 |
+
char byteorder;
|
57 |
+
char flags;
|
58 |
+
int type_num;
|
59 |
+
int elsize;
|
60 |
+
int alignment;
|
61 |
+
char *subarray;
|
62 |
+
PyObject *fields;
|
63 |
+
PyObject *names;
|
64 |
+
};
|
65 |
+
|
66 |
+
struct PyArray_Proxy {
|
67 |
+
PyObject_HEAD
|
68 |
+
char *data;
|
69 |
+
int nd;
|
70 |
+
ssize_t *dimensions;
|
71 |
+
ssize_t *strides;
|
72 |
+
PyObject *base;
|
73 |
+
PyObject *descr;
|
74 |
+
int flags;
|
75 |
+
};
|
76 |
+
|
77 |
+
struct PyVoidScalarObject_Proxy {
|
78 |
+
PyObject_VAR_HEAD
|
79 |
+
char *obval;
|
80 |
+
PyArrayDescr_Proxy *descr;
|
81 |
+
int flags;
|
82 |
+
PyObject *base;
|
83 |
+
};
|
84 |
+
|
85 |
+
struct numpy_type_info {
|
86 |
+
PyObject* dtype_ptr;
|
87 |
+
std::string format_str;
|
88 |
+
};
|
89 |
+
|
90 |
+
struct numpy_internals {
|
91 |
+
std::unordered_map<std::type_index, numpy_type_info> registered_dtypes;
|
92 |
+
|
93 |
+
numpy_type_info *get_type_info(const std::type_info& tinfo, bool throw_if_missing = true) {
|
94 |
+
auto it = registered_dtypes.find(std::type_index(tinfo));
|
95 |
+
if (it != registered_dtypes.end())
|
96 |
+
return &(it->second);
|
97 |
+
if (throw_if_missing)
|
98 |
+
pybind11_fail(std::string("NumPy type info missing for ") + tinfo.name());
|
99 |
+
return nullptr;
|
100 |
+
}
|
101 |
+
|
102 |
+
template<typename T> numpy_type_info *get_type_info(bool throw_if_missing = true) {
|
103 |
+
return get_type_info(typeid(typename std::remove_cv<T>::type), throw_if_missing);
|
104 |
+
}
|
105 |
+
};
|
106 |
+
|
107 |
+
inline PYBIND11_NOINLINE void load_numpy_internals(numpy_internals* &ptr) {
|
108 |
+
ptr = &get_or_create_shared_data<numpy_internals>("_numpy_internals");
|
109 |
+
}
|
110 |
+
|
111 |
+
inline numpy_internals& get_numpy_internals() {
|
112 |
+
static numpy_internals* ptr = nullptr;
|
113 |
+
if (!ptr)
|
114 |
+
load_numpy_internals(ptr);
|
115 |
+
return *ptr;
|
116 |
+
}
|
117 |
+
|
118 |
+
template <typename T> struct same_size {
|
119 |
+
template <typename U> using as = bool_constant<sizeof(T) == sizeof(U)>;
|
120 |
+
};
|
121 |
+
|
122 |
+
template <typename Concrete> constexpr int platform_lookup() { return -1; }
|
123 |
+
|
124 |
+
// Lookup a type according to its size, and return a value corresponding to the NumPy typenum.
|
125 |
+
template <typename Concrete, typename T, typename... Ts, typename... Ints>
|
126 |
+
constexpr int platform_lookup(int I, Ints... Is) {
|
127 |
+
return sizeof(Concrete) == sizeof(T) ? I : platform_lookup<Concrete, Ts...>(Is...);
|
128 |
+
}
|
129 |
+
|
130 |
+
struct npy_api {
|
131 |
+
enum constants {
|
132 |
+
NPY_ARRAY_C_CONTIGUOUS_ = 0x0001,
|
133 |
+
NPY_ARRAY_F_CONTIGUOUS_ = 0x0002,
|
134 |
+
NPY_ARRAY_OWNDATA_ = 0x0004,
|
135 |
+
NPY_ARRAY_FORCECAST_ = 0x0010,
|
136 |
+
NPY_ARRAY_ENSUREARRAY_ = 0x0040,
|
137 |
+
NPY_ARRAY_ALIGNED_ = 0x0100,
|
138 |
+
NPY_ARRAY_WRITEABLE_ = 0x0400,
|
139 |
+
NPY_BOOL_ = 0,
|
140 |
+
NPY_BYTE_, NPY_UBYTE_,
|
141 |
+
NPY_SHORT_, NPY_USHORT_,
|
142 |
+
NPY_INT_, NPY_UINT_,
|
143 |
+
NPY_LONG_, NPY_ULONG_,
|
144 |
+
NPY_LONGLONG_, NPY_ULONGLONG_,
|
145 |
+
NPY_FLOAT_, NPY_DOUBLE_, NPY_LONGDOUBLE_,
|
146 |
+
NPY_CFLOAT_, NPY_CDOUBLE_, NPY_CLONGDOUBLE_,
|
147 |
+
NPY_OBJECT_ = 17,
|
148 |
+
NPY_STRING_, NPY_UNICODE_, NPY_VOID_,
|
149 |
+
// Platform-dependent normalization
|
150 |
+
NPY_INT8_ = NPY_BYTE_,
|
151 |
+
NPY_UINT8_ = NPY_UBYTE_,
|
152 |
+
NPY_INT16_ = NPY_SHORT_,
|
153 |
+
NPY_UINT16_ = NPY_USHORT_,
|
154 |
+
// `npy_common.h` defines the integer aliases. In order, it checks:
|
155 |
+
// NPY_BITSOF_LONG, NPY_BITSOF_LONGLONG, NPY_BITSOF_INT, NPY_BITSOF_SHORT, NPY_BITSOF_CHAR
|
156 |
+
// and assigns the alias to the first matching size, so we should check in this order.
|
157 |
+
NPY_INT32_ = platform_lookup<std::int32_t, long, int, short>(
|
158 |
+
NPY_LONG_, NPY_INT_, NPY_SHORT_),
|
159 |
+
NPY_UINT32_ = platform_lookup<std::uint32_t, unsigned long, unsigned int, unsigned short>(
|
160 |
+
NPY_ULONG_, NPY_UINT_, NPY_USHORT_),
|
161 |
+
NPY_INT64_ = platform_lookup<std::int64_t, long, long long, int>(
|
162 |
+
NPY_LONG_, NPY_LONGLONG_, NPY_INT_),
|
163 |
+
NPY_UINT64_ = platform_lookup<std::uint64_t, unsigned long, unsigned long long, unsigned int>(
|
164 |
+
NPY_ULONG_, NPY_ULONGLONG_, NPY_UINT_),
|
165 |
+
};
|
166 |
+
|
167 |
+
struct PyArray_Dims {
|
168 |
+
Py_intptr_t *ptr;
|
169 |
+
int len;
|
170 |
+
};
|
171 |
+
|
172 |
+
static npy_api& get() {
|
173 |
+
static npy_api api = lookup();
|
174 |
+
return api;
|
175 |
+
}
|
176 |
+
|
177 |
+
bool PyArray_Check_(PyObject *obj) const {
|
178 |
+
return (bool) PyObject_TypeCheck(obj, PyArray_Type_);
|
179 |
+
}
|
180 |
+
bool PyArrayDescr_Check_(PyObject *obj) const {
|
181 |
+
return (bool) PyObject_TypeCheck(obj, PyArrayDescr_Type_);
|
182 |
+
}
|
183 |
+
|
184 |
+
unsigned int (*PyArray_GetNDArrayCFeatureVersion_)();
|
185 |
+
PyObject *(*PyArray_DescrFromType_)(int);
|
186 |
+
PyObject *(*PyArray_NewFromDescr_)
|
187 |
+
(PyTypeObject *, PyObject *, int, Py_intptr_t const *,
|
188 |
+
Py_intptr_t const *, void *, int, PyObject *);
|
189 |
+
// Unused. Not removed because that affects ABI of the class.
|
190 |
+
PyObject *(*PyArray_DescrNewFromType_)(int);
|
191 |
+
int (*PyArray_CopyInto_)(PyObject *, PyObject *);
|
192 |
+
PyObject *(*PyArray_NewCopy_)(PyObject *, int);
|
193 |
+
PyTypeObject *PyArray_Type_;
|
194 |
+
PyTypeObject *PyVoidArrType_Type_;
|
195 |
+
PyTypeObject *PyArrayDescr_Type_;
|
196 |
+
PyObject *(*PyArray_DescrFromScalar_)(PyObject *);
|
197 |
+
PyObject *(*PyArray_FromAny_) (PyObject *, PyObject *, int, int, int, PyObject *);
|
198 |
+
int (*PyArray_DescrConverter_) (PyObject *, PyObject **);
|
199 |
+
bool (*PyArray_EquivTypes_) (PyObject *, PyObject *);
|
200 |
+
int (*PyArray_GetArrayParamsFromObject_)(PyObject *, PyObject *, unsigned char, PyObject **, int *,
|
201 |
+
Py_intptr_t *, PyObject **, PyObject *);
|
202 |
+
PyObject *(*PyArray_Squeeze_)(PyObject *);
|
203 |
+
// Unused. Not removed because that affects ABI of the class.
|
204 |
+
int (*PyArray_SetBaseObject_)(PyObject *, PyObject *);
|
205 |
+
PyObject* (*PyArray_Resize_)(PyObject*, PyArray_Dims*, int, int);
|
206 |
+
private:
|
207 |
+
enum functions {
|
208 |
+
API_PyArray_GetNDArrayCFeatureVersion = 211,
|
209 |
+
API_PyArray_Type = 2,
|
210 |
+
API_PyArrayDescr_Type = 3,
|
211 |
+
API_PyVoidArrType_Type = 39,
|
212 |
+
API_PyArray_DescrFromType = 45,
|
213 |
+
API_PyArray_DescrFromScalar = 57,
|
214 |
+
API_PyArray_FromAny = 69,
|
215 |
+
API_PyArray_Resize = 80,
|
216 |
+
API_PyArray_CopyInto = 82,
|
217 |
+
API_PyArray_NewCopy = 85,
|
218 |
+
API_PyArray_NewFromDescr = 94,
|
219 |
+
API_PyArray_DescrNewFromType = 96,
|
220 |
+
API_PyArray_DescrConverter = 174,
|
221 |
+
API_PyArray_EquivTypes = 182,
|
222 |
+
API_PyArray_GetArrayParamsFromObject = 278,
|
223 |
+
API_PyArray_Squeeze = 136,
|
224 |
+
API_PyArray_SetBaseObject = 282
|
225 |
+
};
|
226 |
+
|
227 |
+
static npy_api lookup() {
|
228 |
+
module_ m = module_::import("numpy.core.multiarray");
|
229 |
+
auto c = m.attr("_ARRAY_API");
|
230 |
+
#if PY_MAJOR_VERSION >= 3
|
231 |
+
void **api_ptr = (void **) PyCapsule_GetPointer(c.ptr(), NULL);
|
232 |
+
#else
|
233 |
+
void **api_ptr = (void **) PyCObject_AsVoidPtr(c.ptr());
|
234 |
+
#endif
|
235 |
+
npy_api api;
|
236 |
+
#define DECL_NPY_API(Func) api.Func##_ = (decltype(api.Func##_)) api_ptr[API_##Func];
|
237 |
+
DECL_NPY_API(PyArray_GetNDArrayCFeatureVersion);
|
238 |
+
if (api.PyArray_GetNDArrayCFeatureVersion_() < 0x7)
|
239 |
+
pybind11_fail("pybind11 numpy support requires numpy >= 1.7.0");
|
240 |
+
DECL_NPY_API(PyArray_Type);
|
241 |
+
DECL_NPY_API(PyVoidArrType_Type);
|
242 |
+
DECL_NPY_API(PyArrayDescr_Type);
|
243 |
+
DECL_NPY_API(PyArray_DescrFromType);
|
244 |
+
DECL_NPY_API(PyArray_DescrFromScalar);
|
245 |
+
DECL_NPY_API(PyArray_FromAny);
|
246 |
+
DECL_NPY_API(PyArray_Resize);
|
247 |
+
DECL_NPY_API(PyArray_CopyInto);
|
248 |
+
DECL_NPY_API(PyArray_NewCopy);
|
249 |
+
DECL_NPY_API(PyArray_NewFromDescr);
|
250 |
+
DECL_NPY_API(PyArray_DescrNewFromType);
|
251 |
+
DECL_NPY_API(PyArray_DescrConverter);
|
252 |
+
DECL_NPY_API(PyArray_EquivTypes);
|
253 |
+
DECL_NPY_API(PyArray_GetArrayParamsFromObject);
|
254 |
+
DECL_NPY_API(PyArray_Squeeze);
|
255 |
+
DECL_NPY_API(PyArray_SetBaseObject);
|
256 |
+
#undef DECL_NPY_API
|
257 |
+
return api;
|
258 |
+
}
|
259 |
+
};
|
260 |
+
|
261 |
+
inline PyArray_Proxy* array_proxy(void* ptr) {
|
262 |
+
return reinterpret_cast<PyArray_Proxy*>(ptr);
|
263 |
+
}
|
264 |
+
|
265 |
+
inline const PyArray_Proxy* array_proxy(const void* ptr) {
|
266 |
+
return reinterpret_cast<const PyArray_Proxy*>(ptr);
|
267 |
+
}
|
268 |
+
|
269 |
+
inline PyArrayDescr_Proxy* array_descriptor_proxy(PyObject* ptr) {
|
270 |
+
return reinterpret_cast<PyArrayDescr_Proxy*>(ptr);
|
271 |
+
}
|
272 |
+
|
273 |
+
inline const PyArrayDescr_Proxy* array_descriptor_proxy(const PyObject* ptr) {
|
274 |
+
return reinterpret_cast<const PyArrayDescr_Proxy*>(ptr);
|
275 |
+
}
|
276 |
+
|
277 |
+
inline bool check_flags(const void* ptr, int flag) {
|
278 |
+
return (flag == (array_proxy(ptr)->flags & flag));
|
279 |
+
}
|
280 |
+
|
281 |
+
template <typename T> struct is_std_array : std::false_type { };
|
282 |
+
template <typename T, size_t N> struct is_std_array<std::array<T, N>> : std::true_type { };
|
283 |
+
template <typename T> struct is_complex : std::false_type { };
|
284 |
+
template <typename T> struct is_complex<std::complex<T>> : std::true_type { };
|
285 |
+
|
286 |
+
template <typename T> struct array_info_scalar {
|
287 |
+
using type = T;
|
288 |
+
static constexpr bool is_array = false;
|
289 |
+
static constexpr bool is_empty = false;
|
290 |
+
static constexpr auto extents = _("");
|
291 |
+
static void append_extents(list& /* shape */) { }
|
292 |
+
};
|
293 |
+
// Computes underlying type and a comma-separated list of extents for array
|
294 |
+
// types (any mix of std::array and built-in arrays). An array of char is
|
295 |
+
// treated as scalar because it gets special handling.
|
296 |
+
template <typename T> struct array_info : array_info_scalar<T> { };
|
297 |
+
template <typename T, size_t N> struct array_info<std::array<T, N>> {
|
298 |
+
using type = typename array_info<T>::type;
|
299 |
+
static constexpr bool is_array = true;
|
300 |
+
static constexpr bool is_empty = (N == 0) || array_info<T>::is_empty;
|
301 |
+
static constexpr size_t extent = N;
|
302 |
+
|
303 |
+
// appends the extents to shape
|
304 |
+
static void append_extents(list& shape) {
|
305 |
+
shape.append(N);
|
306 |
+
array_info<T>::append_extents(shape);
|
307 |
+
}
|
308 |
+
|
309 |
+
static constexpr auto extents = _<array_info<T>::is_array>(
|
310 |
+
concat(_<N>(), array_info<T>::extents), _<N>()
|
311 |
+
);
|
312 |
+
};
|
313 |
+
// For numpy we have special handling for arrays of characters, so we don't include
|
314 |
+
// the size in the array extents.
|
315 |
+
template <size_t N> struct array_info<char[N]> : array_info_scalar<char[N]> { };
|
316 |
+
template <size_t N> struct array_info<std::array<char, N>> : array_info_scalar<std::array<char, N>> { };
|
317 |
+
template <typename T, size_t N> struct array_info<T[N]> : array_info<std::array<T, N>> { };
|
318 |
+
template <typename T> using remove_all_extents_t = typename array_info<T>::type;
|
319 |
+
|
320 |
+
template <typename T> using is_pod_struct = all_of<
|
321 |
+
std::is_standard_layout<T>, // since we're accessing directly in memory we need a standard layout type
|
322 |
+
#if defined(__GLIBCXX__) && (__GLIBCXX__ < 20150422 || __GLIBCXX__ == 20150623 || __GLIBCXX__ == 20150626 || __GLIBCXX__ == 20160803)
|
323 |
+
// libstdc++ < 5 (including versions 4.8.5, 4.9.3 and 4.9.4 which were released after 5)
|
324 |
+
// don't implement is_trivially_copyable, so approximate it
|
325 |
+
std::is_trivially_destructible<T>,
|
326 |
+
satisfies_any_of<T, std::has_trivial_copy_constructor, std::has_trivial_copy_assign>,
|
327 |
+
#else
|
328 |
+
std::is_trivially_copyable<T>,
|
329 |
+
#endif
|
330 |
+
satisfies_none_of<T, std::is_reference, std::is_array, is_std_array, std::is_arithmetic, is_complex, std::is_enum>
|
331 |
+
>;
|
332 |
+
|
333 |
+
// Replacement for std::is_pod (deprecated in C++20)
|
334 |
+
template <typename T> using is_pod = all_of<
|
335 |
+
std::is_standard_layout<T>,
|
336 |
+
std::is_trivial<T>
|
337 |
+
>;
|
338 |
+
|
339 |
+
template <ssize_t Dim = 0, typename Strides> ssize_t byte_offset_unsafe(const Strides &) { return 0; }
|
340 |
+
template <ssize_t Dim = 0, typename Strides, typename... Ix>
|
341 |
+
ssize_t byte_offset_unsafe(const Strides &strides, ssize_t i, Ix... index) {
|
342 |
+
return i * strides[Dim] + byte_offset_unsafe<Dim + 1>(strides, index...);
|
343 |
+
}
|
344 |
+
|
345 |
+
/**
|
346 |
+
* Proxy class providing unsafe, unchecked const access to array data. This is constructed through
|
347 |
+
* the `unchecked<T, N>()` method of `array` or the `unchecked<N>()` method of `array_t<T>`. `Dims`
|
348 |
+
* will be -1 for dimensions determined at runtime.
|
349 |
+
*/
|
350 |
+
template <typename T, ssize_t Dims>
|
351 |
+
class unchecked_reference {
|
352 |
+
protected:
|
353 |
+
static constexpr bool Dynamic = Dims < 0;
|
354 |
+
const unsigned char *data_;
|
355 |
+
// Storing the shape & strides in local variables (i.e. these arrays) allows the compiler to
|
356 |
+
// make large performance gains on big, nested loops, but requires compile-time dimensions
|
357 |
+
conditional_t<Dynamic, const ssize_t *, std::array<ssize_t, (size_t) Dims>>
|
358 |
+
shape_, strides_;
|
359 |
+
const ssize_t dims_;
|
360 |
+
|
361 |
+
friend class pybind11::array;
|
362 |
+
// Constructor for compile-time dimensions:
|
363 |
+
template <bool Dyn = Dynamic>
|
364 |
+
unchecked_reference(const void *data, const ssize_t *shape, const ssize_t *strides, enable_if_t<!Dyn, ssize_t>)
|
365 |
+
: data_{reinterpret_cast<const unsigned char *>(data)}, dims_{Dims} {
|
366 |
+
for (size_t i = 0; i < (size_t) dims_; i++) {
|
367 |
+
shape_[i] = shape[i];
|
368 |
+
strides_[i] = strides[i];
|
369 |
+
}
|
370 |
+
}
|
371 |
+
// Constructor for runtime dimensions:
|
372 |
+
template <bool Dyn = Dynamic>
|
373 |
+
unchecked_reference(const void *data, const ssize_t *shape, const ssize_t *strides, enable_if_t<Dyn, ssize_t> dims)
|
374 |
+
: data_{reinterpret_cast<const unsigned char *>(data)}, shape_{shape}, strides_{strides}, dims_{dims} {}
|
375 |
+
|
376 |
+
public:
|
377 |
+
/**
|
378 |
+
* Unchecked const reference access to data at the given indices. For a compile-time known
|
379 |
+
* number of dimensions, this requires the correct number of arguments; for run-time
|
380 |
+
* dimensionality, this is not checked (and so is up to the caller to use safely).
|
381 |
+
*/
|
382 |
+
template <typename... Ix> const T &operator()(Ix... index) const {
|
383 |
+
static_assert(ssize_t{sizeof...(Ix)} == Dims || Dynamic,
|
384 |
+
"Invalid number of indices for unchecked array reference");
|
385 |
+
return *reinterpret_cast<const T *>(data_ + byte_offset_unsafe(strides_, ssize_t(index)...));
|
386 |
+
}
|
387 |
+
/**
|
388 |
+
* Unchecked const reference access to data; this operator only participates if the reference
|
389 |
+
* is to a 1-dimensional array. When present, this is exactly equivalent to `obj(index)`.
|
390 |
+
*/
|
391 |
+
template <ssize_t D = Dims, typename = enable_if_t<D == 1 || Dynamic>>
|
392 |
+
const T &operator[](ssize_t index) const { return operator()(index); }
|
393 |
+
|
394 |
+
/// Pointer access to the data at the given indices.
|
395 |
+
template <typename... Ix> const T *data(Ix... ix) const { return &operator()(ssize_t(ix)...); }
|
396 |
+
|
397 |
+
/// Returns the item size, i.e. sizeof(T)
|
398 |
+
constexpr static ssize_t itemsize() { return sizeof(T); }
|
399 |
+
|
400 |
+
/// Returns the shape (i.e. size) of dimension `dim`
|
401 |
+
ssize_t shape(ssize_t dim) const { return shape_[(size_t) dim]; }
|
402 |
+
|
403 |
+
/// Returns the number of dimensions of the array
|
404 |
+
ssize_t ndim() const { return dims_; }
|
405 |
+
|
406 |
+
/// Returns the total number of elements in the referenced array, i.e. the product of the shapes
|
407 |
+
template <bool Dyn = Dynamic>
|
408 |
+
enable_if_t<!Dyn, ssize_t> size() const {
|
409 |
+
return std::accumulate(shape_.begin(), shape_.end(), (ssize_t) 1, std::multiplies<ssize_t>());
|
410 |
+
}
|
411 |
+
template <bool Dyn = Dynamic>
|
412 |
+
enable_if_t<Dyn, ssize_t> size() const {
|
413 |
+
return std::accumulate(shape_, shape_ + ndim(), (ssize_t) 1, std::multiplies<ssize_t>());
|
414 |
+
}
|
415 |
+
|
416 |
+
/// Returns the total number of bytes used by the referenced data. Note that the actual span in
|
417 |
+
/// memory may be larger if the referenced array has non-contiguous strides (e.g. for a slice).
|
418 |
+
ssize_t nbytes() const {
|
419 |
+
return size() * itemsize();
|
420 |
+
}
|
421 |
+
};
|
422 |
+
|
423 |
+
template <typename T, ssize_t Dims>
|
424 |
+
class unchecked_mutable_reference : public unchecked_reference<T, Dims> {
|
425 |
+
friend class pybind11::array;
|
426 |
+
using ConstBase = unchecked_reference<T, Dims>;
|
427 |
+
using ConstBase::ConstBase;
|
428 |
+
using ConstBase::Dynamic;
|
429 |
+
public:
|
430 |
+
// Bring in const-qualified versions from base class
|
431 |
+
using ConstBase::operator();
|
432 |
+
using ConstBase::operator[];
|
433 |
+
|
434 |
+
/// Mutable, unchecked access to data at the given indices.
|
435 |
+
template <typename... Ix> T& operator()(Ix... index) {
|
436 |
+
static_assert(ssize_t{sizeof...(Ix)} == Dims || Dynamic,
|
437 |
+
"Invalid number of indices for unchecked array reference");
|
438 |
+
return const_cast<T &>(ConstBase::operator()(index...));
|
439 |
+
}
|
440 |
+
/**
|
441 |
+
* Mutable, unchecked access data at the given index; this operator only participates if the
|
442 |
+
* reference is to a 1-dimensional array (or has runtime dimensions). When present, this is
|
443 |
+
* exactly equivalent to `obj(index)`.
|
444 |
+
*/
|
445 |
+
template <ssize_t D = Dims, typename = enable_if_t<D == 1 || Dynamic>>
|
446 |
+
T &operator[](ssize_t index) { return operator()(index); }
|
447 |
+
|
448 |
+
/// Mutable pointer access to the data at the given indices.
|
449 |
+
template <typename... Ix> T *mutable_data(Ix... ix) { return &operator()(ssize_t(ix)...); }
|
450 |
+
};
|
451 |
+
|
452 |
+
template <typename T, ssize_t Dim>
|
453 |
+
struct type_caster<unchecked_reference<T, Dim>> {
|
454 |
+
static_assert(Dim == 0 && Dim > 0 /* always fail */, "unchecked array proxy object is not castable");
|
455 |
+
};
|
456 |
+
template <typename T, ssize_t Dim>
|
457 |
+
struct type_caster<unchecked_mutable_reference<T, Dim>> : type_caster<unchecked_reference<T, Dim>> {};
|
458 |
+
|
459 |
+
PYBIND11_NAMESPACE_END(detail)
|
460 |
+
|
461 |
+
class dtype : public object {
|
462 |
+
public:
|
463 |
+
PYBIND11_OBJECT_DEFAULT(dtype, object, detail::npy_api::get().PyArrayDescr_Check_);
|
464 |
+
|
465 |
+
explicit dtype(const buffer_info &info) {
|
466 |
+
dtype descr(_dtype_from_pep3118()(PYBIND11_STR_TYPE(info.format)));
|
467 |
+
// If info.itemsize == 0, use the value calculated from the format string
|
468 |
+
m_ptr = descr.strip_padding(info.itemsize != 0 ? info.itemsize : descr.itemsize())
|
469 |
+
.release()
|
470 |
+
.ptr();
|
471 |
+
}
|
472 |
+
|
473 |
+
explicit dtype(const std::string &format) {
|
474 |
+
m_ptr = from_args(pybind11::str(format)).release().ptr();
|
475 |
+
}
|
476 |
+
|
477 |
+
dtype(const char *format) : dtype(std::string(format)) { }
|
478 |
+
|
479 |
+
dtype(list names, list formats, list offsets, ssize_t itemsize) {
|
480 |
+
dict args;
|
481 |
+
args["names"] = names;
|
482 |
+
args["formats"] = formats;
|
483 |
+
args["offsets"] = offsets;
|
484 |
+
args["itemsize"] = pybind11::int_(itemsize);
|
485 |
+
m_ptr = from_args(args).release().ptr();
|
486 |
+
}
|
487 |
+
|
488 |
+
/// This is essentially the same as calling numpy.dtype(args) in Python.
|
489 |
+
static dtype from_args(object args) {
|
490 |
+
PyObject *ptr = nullptr;
|
491 |
+
if ((detail::npy_api::get().PyArray_DescrConverter_(args.ptr(), &ptr) == 0) || !ptr)
|
492 |
+
throw error_already_set();
|
493 |
+
return reinterpret_steal<dtype>(ptr);
|
494 |
+
}
|
495 |
+
|
496 |
+
/// Return dtype associated with a C++ type.
|
497 |
+
template <typename T> static dtype of() {
|
498 |
+
return detail::npy_format_descriptor<typename std::remove_cv<T>::type>::dtype();
|
499 |
+
}
|
500 |
+
|
501 |
+
/// Size of the data type in bytes.
|
502 |
+
ssize_t itemsize() const {
|
503 |
+
return detail::array_descriptor_proxy(m_ptr)->elsize;
|
504 |
+
}
|
505 |
+
|
506 |
+
/// Returns true for structured data types.
|
507 |
+
bool has_fields() const {
|
508 |
+
return detail::array_descriptor_proxy(m_ptr)->names != nullptr;
|
509 |
+
}
|
510 |
+
|
511 |
+
/// Single-character code for dtype's kind.
|
512 |
+
/// For example, floating point types are 'f' and integral types are 'i'.
|
513 |
+
char kind() const {
|
514 |
+
return detail::array_descriptor_proxy(m_ptr)->kind;
|
515 |
+
}
|
516 |
+
|
517 |
+
/// Single-character for dtype's type.
|
518 |
+
/// For example, ``float`` is 'f', ``double`` 'd', ``int`` 'i', and ``long`` 'd'.
|
519 |
+
char char_() const {
|
520 |
+
// Note: The signature, `dtype::char_` follows the naming of NumPy's
|
521 |
+
// public Python API (i.e., ``dtype.char``), rather than its internal
|
522 |
+
// C API (``PyArray_Descr::type``).
|
523 |
+
return detail::array_descriptor_proxy(m_ptr)->type;
|
524 |
+
}
|
525 |
+
|
526 |
+
private:
|
527 |
+
static object _dtype_from_pep3118() {
|
528 |
+
static PyObject *obj = module_::import("numpy.core._internal")
|
529 |
+
.attr("_dtype_from_pep3118").cast<object>().release().ptr();
|
530 |
+
return reinterpret_borrow<object>(obj);
|
531 |
+
}
|
532 |
+
|
533 |
+
dtype strip_padding(ssize_t itemsize) {
|
534 |
+
// Recursively strip all void fields with empty names that are generated for
|
535 |
+
// padding fields (as of NumPy v1.11).
|
536 |
+
if (!has_fields())
|
537 |
+
return *this;
|
538 |
+
|
539 |
+
struct field_descr { PYBIND11_STR_TYPE name; object format; pybind11::int_ offset; };
|
540 |
+
std::vector<field_descr> field_descriptors;
|
541 |
+
|
542 |
+
for (auto field : attr("fields").attr("items")()) {
|
543 |
+
auto spec = field.cast<tuple>();
|
544 |
+
auto name = spec[0].cast<pybind11::str>();
|
545 |
+
auto format = spec[1].cast<tuple>()[0].cast<dtype>();
|
546 |
+
auto offset = spec[1].cast<tuple>()[1].cast<pybind11::int_>();
|
547 |
+
if ((len(name) == 0u) && format.kind() == 'V')
|
548 |
+
continue;
|
549 |
+
field_descriptors.push_back({(PYBIND11_STR_TYPE) name, format.strip_padding(format.itemsize()), offset});
|
550 |
+
}
|
551 |
+
|
552 |
+
std::sort(field_descriptors.begin(), field_descriptors.end(),
|
553 |
+
[](const field_descr& a, const field_descr& b) {
|
554 |
+
return a.offset.cast<int>() < b.offset.cast<int>();
|
555 |
+
});
|
556 |
+
|
557 |
+
list names, formats, offsets;
|
558 |
+
for (auto& descr : field_descriptors) {
|
559 |
+
names.append(descr.name);
|
560 |
+
formats.append(descr.format);
|
561 |
+
offsets.append(descr.offset);
|
562 |
+
}
|
563 |
+
return dtype(names, formats, offsets, itemsize);
|
564 |
+
}
|
565 |
+
};
|
566 |
+
|
567 |
+
class array : public buffer {
|
568 |
+
public:
|
569 |
+
PYBIND11_OBJECT_CVT(array, buffer, detail::npy_api::get().PyArray_Check_, raw_array)
|
570 |
+
|
571 |
+
enum {
|
572 |
+
c_style = detail::npy_api::NPY_ARRAY_C_CONTIGUOUS_,
|
573 |
+
f_style = detail::npy_api::NPY_ARRAY_F_CONTIGUOUS_,
|
574 |
+
forcecast = detail::npy_api::NPY_ARRAY_FORCECAST_
|
575 |
+
};
|
576 |
+
|
577 |
+
array() : array(0, static_cast<const double *>(nullptr)) {}
|
578 |
+
|
579 |
+
using ShapeContainer = detail::any_container<ssize_t>;
|
580 |
+
using StridesContainer = detail::any_container<ssize_t>;
|
581 |
+
|
582 |
+
// Constructs an array taking shape/strides from arbitrary container types
|
583 |
+
array(const pybind11::dtype &dt, ShapeContainer shape, StridesContainer strides,
|
584 |
+
const void *ptr = nullptr, handle base = handle()) {
|
585 |
+
|
586 |
+
if (strides->empty())
|
587 |
+
*strides = detail::c_strides(*shape, dt.itemsize());
|
588 |
+
|
589 |
+
auto ndim = shape->size();
|
590 |
+
if (ndim != strides->size())
|
591 |
+
pybind11_fail("NumPy: shape ndim doesn't match strides ndim");
|
592 |
+
auto descr = dt;
|
593 |
+
|
594 |
+
int flags = 0;
|
595 |
+
if (base && ptr) {
|
596 |
+
if (isinstance<array>(base))
|
597 |
+
/* Copy flags from base (except ownership bit) */
|
598 |
+
flags = reinterpret_borrow<array>(base).flags() & ~detail::npy_api::NPY_ARRAY_OWNDATA_;
|
599 |
+
else
|
600 |
+
/* Writable by default, easy to downgrade later on if needed */
|
601 |
+
flags = detail::npy_api::NPY_ARRAY_WRITEABLE_;
|
602 |
+
}
|
603 |
+
|
604 |
+
auto &api = detail::npy_api::get();
|
605 |
+
auto tmp = reinterpret_steal<object>(api.PyArray_NewFromDescr_(
|
606 |
+
api.PyArray_Type_, descr.release().ptr(), (int) ndim,
|
607 |
+
// Use reinterpret_cast for PyPy on Windows (remove if fixed, checked on 7.3.1)
|
608 |
+
reinterpret_cast<Py_intptr_t*>(shape->data()),
|
609 |
+
reinterpret_cast<Py_intptr_t*>(strides->data()),
|
610 |
+
const_cast<void *>(ptr), flags, nullptr));
|
611 |
+
if (!tmp)
|
612 |
+
throw error_already_set();
|
613 |
+
if (ptr) {
|
614 |
+
if (base) {
|
615 |
+
api.PyArray_SetBaseObject_(tmp.ptr(), base.inc_ref().ptr());
|
616 |
+
} else {
|
617 |
+
tmp = reinterpret_steal<object>(api.PyArray_NewCopy_(tmp.ptr(), -1 /* any order */));
|
618 |
+
}
|
619 |
+
}
|
620 |
+
m_ptr = tmp.release().ptr();
|
621 |
+
}
|
622 |
+
|
623 |
+
array(const pybind11::dtype &dt, ShapeContainer shape, const void *ptr = nullptr, handle base = handle())
|
624 |
+
: array(dt, std::move(shape), {}, ptr, base) { }
|
625 |
+
|
626 |
+
template <typename T, typename = detail::enable_if_t<std::is_integral<T>::value && !std::is_same<bool, T>::value>>
|
627 |
+
array(const pybind11::dtype &dt, T count, const void *ptr = nullptr, handle base = handle())
|
628 |
+
: array(dt, {{count}}, ptr, base) { }
|
629 |
+
|
630 |
+
template <typename T>
|
631 |
+
array(ShapeContainer shape, StridesContainer strides, const T *ptr, handle base = handle())
|
632 |
+
: array(pybind11::dtype::of<T>(), std::move(shape), std::move(strides), ptr, base) { }
|
633 |
+
|
634 |
+
template <typename T>
|
635 |
+
array(ShapeContainer shape, const T *ptr, handle base = handle())
|
636 |
+
: array(std::move(shape), {}, ptr, base) { }
|
637 |
+
|
638 |
+
template <typename T>
|
639 |
+
explicit array(ssize_t count, const T *ptr, handle base = handle()) : array({count}, {}, ptr, base) { }
|
640 |
+
|
641 |
+
explicit array(const buffer_info &info, handle base = handle())
|
642 |
+
: array(pybind11::dtype(info), info.shape, info.strides, info.ptr, base) { }
|
643 |
+
|
644 |
+
/// Array descriptor (dtype)
|
645 |
+
pybind11::dtype dtype() const {
|
646 |
+
return reinterpret_borrow<pybind11::dtype>(detail::array_proxy(m_ptr)->descr);
|
647 |
+
}
|
648 |
+
|
649 |
+
/// Total number of elements
|
650 |
+
ssize_t size() const {
|
651 |
+
return std::accumulate(shape(), shape() + ndim(), (ssize_t) 1, std::multiplies<ssize_t>());
|
652 |
+
}
|
653 |
+
|
654 |
+
/// Byte size of a single element
|
655 |
+
ssize_t itemsize() const {
|
656 |
+
return detail::array_descriptor_proxy(detail::array_proxy(m_ptr)->descr)->elsize;
|
657 |
+
}
|
658 |
+
|
659 |
+
/// Total number of bytes
|
660 |
+
ssize_t nbytes() const {
|
661 |
+
return size() * itemsize();
|
662 |
+
}
|
663 |
+
|
664 |
+
/// Number of dimensions
|
665 |
+
ssize_t ndim() const {
|
666 |
+
return detail::array_proxy(m_ptr)->nd;
|
667 |
+
}
|
668 |
+
|
669 |
+
/// Base object
|
670 |
+
object base() const {
|
671 |
+
return reinterpret_borrow<object>(detail::array_proxy(m_ptr)->base);
|
672 |
+
}
|
673 |
+
|
674 |
+
/// Dimensions of the array
|
675 |
+
const ssize_t* shape() const {
|
676 |
+
return detail::array_proxy(m_ptr)->dimensions;
|
677 |
+
}
|
678 |
+
|
679 |
+
/// Dimension along a given axis
|
680 |
+
ssize_t shape(ssize_t dim) const {
|
681 |
+
if (dim >= ndim())
|
682 |
+
fail_dim_check(dim, "invalid axis");
|
683 |
+
return shape()[dim];
|
684 |
+
}
|
685 |
+
|
686 |
+
/// Strides of the array
|
687 |
+
const ssize_t* strides() const {
|
688 |
+
return detail::array_proxy(m_ptr)->strides;
|
689 |
+
}
|
690 |
+
|
691 |
+
/// Stride along a given axis
|
692 |
+
ssize_t strides(ssize_t dim) const {
|
693 |
+
if (dim >= ndim())
|
694 |
+
fail_dim_check(dim, "invalid axis");
|
695 |
+
return strides()[dim];
|
696 |
+
}
|
697 |
+
|
698 |
+
/// Return the NumPy array flags
|
699 |
+
int flags() const {
|
700 |
+
return detail::array_proxy(m_ptr)->flags;
|
701 |
+
}
|
702 |
+
|
703 |
+
/// If set, the array is writeable (otherwise the buffer is read-only)
|
704 |
+
bool writeable() const {
|
705 |
+
return detail::check_flags(m_ptr, detail::npy_api::NPY_ARRAY_WRITEABLE_);
|
706 |
+
}
|
707 |
+
|
708 |
+
/// If set, the array owns the data (will be freed when the array is deleted)
|
709 |
+
bool owndata() const {
|
710 |
+
return detail::check_flags(m_ptr, detail::npy_api::NPY_ARRAY_OWNDATA_);
|
711 |
+
}
|
712 |
+
|
713 |
+
/// Pointer to the contained data. If index is not provided, points to the
|
714 |
+
/// beginning of the buffer. May throw if the index would lead to out of bounds access.
|
715 |
+
template<typename... Ix> const void* data(Ix... index) const {
|
716 |
+
return static_cast<const void *>(detail::array_proxy(m_ptr)->data + offset_at(index...));
|
717 |
+
}
|
718 |
+
|
719 |
+
/// Mutable pointer to the contained data. If index is not provided, points to the
|
720 |
+
/// beginning of the buffer. May throw if the index would lead to out of bounds access.
|
721 |
+
/// May throw if the array is not writeable.
|
722 |
+
template<typename... Ix> void* mutable_data(Ix... index) {
|
723 |
+
check_writeable();
|
724 |
+
return static_cast<void *>(detail::array_proxy(m_ptr)->data + offset_at(index...));
|
725 |
+
}
|
726 |
+
|
727 |
+
/// Byte offset from beginning of the array to a given index (full or partial).
|
728 |
+
/// May throw if the index would lead to out of bounds access.
|
729 |
+
template<typename... Ix> ssize_t offset_at(Ix... index) const {
|
730 |
+
if ((ssize_t) sizeof...(index) > ndim())
|
731 |
+
fail_dim_check(sizeof...(index), "too many indices for an array");
|
732 |
+
return byte_offset(ssize_t(index)...);
|
733 |
+
}
|
734 |
+
|
735 |
+
ssize_t offset_at() const { return 0; }
|
736 |
+
|
737 |
+
/// Item count from beginning of the array to a given index (full or partial).
|
738 |
+
/// May throw if the index would lead to out of bounds access.
|
739 |
+
template<typename... Ix> ssize_t index_at(Ix... index) const {
|
740 |
+
return offset_at(index...) / itemsize();
|
741 |
+
}
|
742 |
+
|
743 |
+
/**
|
744 |
+
* Returns a proxy object that provides access to the array's data without bounds or
|
745 |
+
* dimensionality checking. Will throw if the array is missing the `writeable` flag. Use with
|
746 |
+
* care: the array must not be destroyed or reshaped for the duration of the returned object,
|
747 |
+
* and the caller must take care not to access invalid dimensions or dimension indices.
|
748 |
+
*/
|
749 |
+
template <typename T, ssize_t Dims = -1> detail::unchecked_mutable_reference<T, Dims> mutable_unchecked() & {
|
750 |
+
if (Dims >= 0 && ndim() != Dims)
|
751 |
+
throw std::domain_error("array has incorrect number of dimensions: " + std::to_string(ndim()) +
|
752 |
+
"; expected " + std::to_string(Dims));
|
753 |
+
return detail::unchecked_mutable_reference<T, Dims>(mutable_data(), shape(), strides(), ndim());
|
754 |
+
}
|
755 |
+
|
756 |
+
/**
|
757 |
+
* Returns a proxy object that provides const access to the array's data without bounds or
|
758 |
+
* dimensionality checking. Unlike `mutable_unchecked()`, this does not require that the
|
759 |
+
* underlying array have the `writable` flag. Use with care: the array must not be destroyed or
|
760 |
+
* reshaped for the duration of the returned object, and the caller must take care not to access
|
761 |
+
* invalid dimensions or dimension indices.
|
762 |
+
*/
|
763 |
+
template <typename T, ssize_t Dims = -1> detail::unchecked_reference<T, Dims> unchecked() const & {
|
764 |
+
if (Dims >= 0 && ndim() != Dims)
|
765 |
+
throw std::domain_error("array has incorrect number of dimensions: " + std::to_string(ndim()) +
|
766 |
+
"; expected " + std::to_string(Dims));
|
767 |
+
return detail::unchecked_reference<T, Dims>(data(), shape(), strides(), ndim());
|
768 |
+
}
|
769 |
+
|
770 |
+
/// Return a new view with all of the dimensions of length 1 removed
|
771 |
+
array squeeze() {
|
772 |
+
auto& api = detail::npy_api::get();
|
773 |
+
return reinterpret_steal<array>(api.PyArray_Squeeze_(m_ptr));
|
774 |
+
}
|
775 |
+
|
776 |
+
/// Resize array to given shape
|
777 |
+
/// If refcheck is true and more that one reference exist to this array
|
778 |
+
/// then resize will succeed only if it makes a reshape, i.e. original size doesn't change
|
779 |
+
void resize(ShapeContainer new_shape, bool refcheck = true) {
|
780 |
+
detail::npy_api::PyArray_Dims d = {
|
781 |
+
// Use reinterpret_cast for PyPy on Windows (remove if fixed, checked on 7.3.1)
|
782 |
+
reinterpret_cast<Py_intptr_t*>(new_shape->data()),
|
783 |
+
int(new_shape->size())
|
784 |
+
};
|
785 |
+
// try to resize, set ordering param to -1 cause it's not used anyway
|
786 |
+
auto new_array = reinterpret_steal<object>(
|
787 |
+
detail::npy_api::get().PyArray_Resize_(m_ptr, &d, int(refcheck), -1)
|
788 |
+
);
|
789 |
+
if (!new_array) throw error_already_set();
|
790 |
+
if (isinstance<array>(new_array)) { *this = std::move(new_array); }
|
791 |
+
}
|
792 |
+
|
793 |
+
/// Ensure that the argument is a NumPy array
|
794 |
+
/// In case of an error, nullptr is returned and the Python error is cleared.
|
795 |
+
static array ensure(handle h, int ExtraFlags = 0) {
|
796 |
+
auto result = reinterpret_steal<array>(raw_array(h.ptr(), ExtraFlags));
|
797 |
+
if (!result)
|
798 |
+
PyErr_Clear();
|
799 |
+
return result;
|
800 |
+
}
|
801 |
+
|
802 |
+
protected:
|
803 |
+
template<typename, typename> friend struct detail::npy_format_descriptor;
|
804 |
+
|
805 |
+
void fail_dim_check(ssize_t dim, const std::string& msg) const {
|
806 |
+
throw index_error(msg + ": " + std::to_string(dim) +
|
807 |
+
" (ndim = " + std::to_string(ndim()) + ")");
|
808 |
+
}
|
809 |
+
|
810 |
+
template<typename... Ix> ssize_t byte_offset(Ix... index) const {
|
811 |
+
check_dimensions(index...);
|
812 |
+
return detail::byte_offset_unsafe(strides(), ssize_t(index)...);
|
813 |
+
}
|
814 |
+
|
815 |
+
void check_writeable() const {
|
816 |
+
if (!writeable())
|
817 |
+
throw std::domain_error("array is not writeable");
|
818 |
+
}
|
819 |
+
|
820 |
+
template<typename... Ix> void check_dimensions(Ix... index) const {
|
821 |
+
check_dimensions_impl(ssize_t(0), shape(), ssize_t(index)...);
|
822 |
+
}
|
823 |
+
|
824 |
+
void check_dimensions_impl(ssize_t, const ssize_t*) const { }
|
825 |
+
|
826 |
+
template<typename... Ix> void check_dimensions_impl(ssize_t axis, const ssize_t* shape, ssize_t i, Ix... index) const {
|
827 |
+
if (i >= *shape) {
|
828 |
+
throw index_error(std::string("index ") + std::to_string(i) +
|
829 |
+
" is out of bounds for axis " + std::to_string(axis) +
|
830 |
+
" with size " + std::to_string(*shape));
|
831 |
+
}
|
832 |
+
check_dimensions_impl(axis + 1, shape + 1, index...);
|
833 |
+
}
|
834 |
+
|
835 |
+
/// Create array from any object -- always returns a new reference
|
836 |
+
static PyObject *raw_array(PyObject *ptr, int ExtraFlags = 0) {
|
837 |
+
if (ptr == nullptr) {
|
838 |
+
PyErr_SetString(PyExc_ValueError, "cannot create a pybind11::array from a nullptr");
|
839 |
+
return nullptr;
|
840 |
+
}
|
841 |
+
return detail::npy_api::get().PyArray_FromAny_(
|
842 |
+
ptr, nullptr, 0, 0, detail::npy_api::NPY_ARRAY_ENSUREARRAY_ | ExtraFlags, nullptr);
|
843 |
+
}
|
844 |
+
};
|
845 |
+
|
846 |
+
template <typename T, int ExtraFlags = array::forcecast> class array_t : public array {
|
847 |
+
private:
|
848 |
+
struct private_ctor {};
|
849 |
+
// Delegating constructor needed when both moving and accessing in the same constructor
|
850 |
+
array_t(private_ctor, ShapeContainer &&shape, StridesContainer &&strides, const T *ptr, handle base)
|
851 |
+
: array(std::move(shape), std::move(strides), ptr, base) {}
|
852 |
+
public:
|
853 |
+
static_assert(!detail::array_info<T>::is_array, "Array types cannot be used with array_t");
|
854 |
+
|
855 |
+
using value_type = T;
|
856 |
+
|
857 |
+
array_t() : array(0, static_cast<const T *>(nullptr)) {}
|
858 |
+
array_t(handle h, borrowed_t) : array(h, borrowed_t{}) { }
|
859 |
+
array_t(handle h, stolen_t) : array(h, stolen_t{}) { }
|
860 |
+
|
861 |
+
PYBIND11_DEPRECATED("Use array_t<T>::ensure() instead")
|
862 |
+
array_t(handle h, bool is_borrowed) : array(raw_array_t(h.ptr()), stolen_t{}) {
|
863 |
+
if (!m_ptr) PyErr_Clear();
|
864 |
+
if (!is_borrowed) Py_XDECREF(h.ptr());
|
865 |
+
}
|
866 |
+
|
867 |
+
array_t(const object &o) : array(raw_array_t(o.ptr()), stolen_t{}) {
|
868 |
+
if (!m_ptr) throw error_already_set();
|
869 |
+
}
|
870 |
+
|
871 |
+
explicit array_t(const buffer_info& info, handle base = handle()) : array(info, base) { }
|
872 |
+
|
873 |
+
array_t(ShapeContainer shape, StridesContainer strides, const T *ptr = nullptr, handle base = handle())
|
874 |
+
: array(std::move(shape), std::move(strides), ptr, base) { }
|
875 |
+
|
876 |
+
explicit array_t(ShapeContainer shape, const T *ptr = nullptr, handle base = handle())
|
877 |
+
: array_t(private_ctor{},
|
878 |
+
std::move(shape),
|
879 |
+
(ExtraFlags & f_style) != 0 ? detail::f_strides(*shape, itemsize())
|
880 |
+
: detail::c_strides(*shape, itemsize()),
|
881 |
+
ptr,
|
882 |
+
base) {}
|
883 |
+
|
884 |
+
explicit array_t(ssize_t count, const T *ptr = nullptr, handle base = handle())
|
885 |
+
: array({count}, {}, ptr, base) { }
|
886 |
+
|
887 |
+
constexpr ssize_t itemsize() const {
|
888 |
+
return sizeof(T);
|
889 |
+
}
|
890 |
+
|
891 |
+
template<typename... Ix> ssize_t index_at(Ix... index) const {
|
892 |
+
return offset_at(index...) / itemsize();
|
893 |
+
}
|
894 |
+
|
895 |
+
template<typename... Ix> const T* data(Ix... index) const {
|
896 |
+
return static_cast<const T*>(array::data(index...));
|
897 |
+
}
|
898 |
+
|
899 |
+
template<typename... Ix> T* mutable_data(Ix... index) {
|
900 |
+
return static_cast<T*>(array::mutable_data(index...));
|
901 |
+
}
|
902 |
+
|
903 |
+
// Reference to element at a given index
|
904 |
+
template<typename... Ix> const T& at(Ix... index) const {
|
905 |
+
if ((ssize_t) sizeof...(index) != ndim())
|
906 |
+
fail_dim_check(sizeof...(index), "index dimension mismatch");
|
907 |
+
return *(static_cast<const T*>(array::data()) + byte_offset(ssize_t(index)...) / itemsize());
|
908 |
+
}
|
909 |
+
|
910 |
+
// Mutable reference to element at a given index
|
911 |
+
template<typename... Ix> T& mutable_at(Ix... index) {
|
912 |
+
if ((ssize_t) sizeof...(index) != ndim())
|
913 |
+
fail_dim_check(sizeof...(index), "index dimension mismatch");
|
914 |
+
return *(static_cast<T*>(array::mutable_data()) + byte_offset(ssize_t(index)...) / itemsize());
|
915 |
+
}
|
916 |
+
|
917 |
+
/**
|
918 |
+
* Returns a proxy object that provides access to the array's data without bounds or
|
919 |
+
* dimensionality checking. Will throw if the array is missing the `writeable` flag. Use with
|
920 |
+
* care: the array must not be destroyed or reshaped for the duration of the returned object,
|
921 |
+
* and the caller must take care not to access invalid dimensions or dimension indices.
|
922 |
+
*/
|
923 |
+
template <ssize_t Dims = -1> detail::unchecked_mutable_reference<T, Dims> mutable_unchecked() & {
|
924 |
+
return array::mutable_unchecked<T, Dims>();
|
925 |
+
}
|
926 |
+
|
927 |
+
/**
|
928 |
+
* Returns a proxy object that provides const access to the array's data without bounds or
|
929 |
+
* dimensionality checking. Unlike `unchecked()`, this does not require that the underlying
|
930 |
+
* array have the `writable` flag. Use with care: the array must not be destroyed or reshaped
|
931 |
+
* for the duration of the returned object, and the caller must take care not to access invalid
|
932 |
+
* dimensions or dimension indices.
|
933 |
+
*/
|
934 |
+
template <ssize_t Dims = -1> detail::unchecked_reference<T, Dims> unchecked() const & {
|
935 |
+
return array::unchecked<T, Dims>();
|
936 |
+
}
|
937 |
+
|
938 |
+
/// Ensure that the argument is a NumPy array of the correct dtype (and if not, try to convert
|
939 |
+
/// it). In case of an error, nullptr is returned and the Python error is cleared.
|
940 |
+
static array_t ensure(handle h) {
|
941 |
+
auto result = reinterpret_steal<array_t>(raw_array_t(h.ptr()));
|
942 |
+
if (!result)
|
943 |
+
PyErr_Clear();
|
944 |
+
return result;
|
945 |
+
}
|
946 |
+
|
947 |
+
static bool check_(handle h) {
|
948 |
+
const auto &api = detail::npy_api::get();
|
949 |
+
return api.PyArray_Check_(h.ptr())
|
950 |
+
&& api.PyArray_EquivTypes_(detail::array_proxy(h.ptr())->descr, dtype::of<T>().ptr())
|
951 |
+
&& detail::check_flags(h.ptr(), ExtraFlags & (array::c_style | array::f_style));
|
952 |
+
}
|
953 |
+
|
954 |
+
protected:
|
955 |
+
/// Create array from any object -- always returns a new reference
|
956 |
+
static PyObject *raw_array_t(PyObject *ptr) {
|
957 |
+
if (ptr == nullptr) {
|
958 |
+
PyErr_SetString(PyExc_ValueError, "cannot create a pybind11::array_t from a nullptr");
|
959 |
+
return nullptr;
|
960 |
+
}
|
961 |
+
return detail::npy_api::get().PyArray_FromAny_(
|
962 |
+
ptr, dtype::of<T>().release().ptr(), 0, 0,
|
963 |
+
detail::npy_api::NPY_ARRAY_ENSUREARRAY_ | ExtraFlags, nullptr);
|
964 |
+
}
|
965 |
+
};
|
966 |
+
|
967 |
+
template <typename T>
|
968 |
+
struct format_descriptor<T, detail::enable_if_t<detail::is_pod_struct<T>::value>> {
|
969 |
+
static std::string format() {
|
970 |
+
return detail::npy_format_descriptor<typename std::remove_cv<T>::type>::format();
|
971 |
+
}
|
972 |
+
};
|
973 |
+
|
974 |
+
template <size_t N> struct format_descriptor<char[N]> {
|
975 |
+
static std::string format() { return std::to_string(N) + "s"; }
|
976 |
+
};
|
977 |
+
template <size_t N> struct format_descriptor<std::array<char, N>> {
|
978 |
+
static std::string format() { return std::to_string(N) + "s"; }
|
979 |
+
};
|
980 |
+
|
981 |
+
template <typename T>
|
982 |
+
struct format_descriptor<T, detail::enable_if_t<std::is_enum<T>::value>> {
|
983 |
+
static std::string format() {
|
984 |
+
return format_descriptor<
|
985 |
+
typename std::remove_cv<typename std::underlying_type<T>::type>::type>::format();
|
986 |
+
}
|
987 |
+
};
|
988 |
+
|
989 |
+
template <typename T>
|
990 |
+
struct format_descriptor<T, detail::enable_if_t<detail::array_info<T>::is_array>> {
|
991 |
+
static std::string format() {
|
992 |
+
using namespace detail;
|
993 |
+
static constexpr auto extents = _("(") + array_info<T>::extents + _(")");
|
994 |
+
return extents.text + format_descriptor<remove_all_extents_t<T>>::format();
|
995 |
+
}
|
996 |
+
};
|
997 |
+
|
998 |
+
PYBIND11_NAMESPACE_BEGIN(detail)
|
999 |
+
template <typename T, int ExtraFlags>
|
1000 |
+
struct pyobject_caster<array_t<T, ExtraFlags>> {
|
1001 |
+
using type = array_t<T, ExtraFlags>;
|
1002 |
+
|
1003 |
+
bool load(handle src, bool convert) {
|
1004 |
+
if (!convert && !type::check_(src))
|
1005 |
+
return false;
|
1006 |
+
value = type::ensure(src);
|
1007 |
+
return static_cast<bool>(value);
|
1008 |
+
}
|
1009 |
+
|
1010 |
+
static handle cast(const handle &src, return_value_policy /* policy */, handle /* parent */) {
|
1011 |
+
return src.inc_ref();
|
1012 |
+
}
|
1013 |
+
PYBIND11_TYPE_CASTER(type, handle_type_name<type>::name);
|
1014 |
+
};
|
1015 |
+
|
1016 |
+
template <typename T>
|
1017 |
+
struct compare_buffer_info<T, detail::enable_if_t<detail::is_pod_struct<T>::value>> {
|
1018 |
+
static bool compare(const buffer_info& b) {
|
1019 |
+
return npy_api::get().PyArray_EquivTypes_(dtype::of<T>().ptr(), dtype(b).ptr());
|
1020 |
+
}
|
1021 |
+
};
|
1022 |
+
|
1023 |
+
template <typename T, typename = void>
|
1024 |
+
struct npy_format_descriptor_name;
|
1025 |
+
|
1026 |
+
template <typename T>
|
1027 |
+
struct npy_format_descriptor_name<T, enable_if_t<std::is_integral<T>::value>> {
|
1028 |
+
static constexpr auto name = _<std::is_same<T, bool>::value>(
|
1029 |
+
_("bool"), _<std::is_signed<T>::value>("numpy.int", "numpy.uint") + _<sizeof(T)*8>()
|
1030 |
+
);
|
1031 |
+
};
|
1032 |
+
|
1033 |
+
template <typename T>
|
1034 |
+
struct npy_format_descriptor_name<T, enable_if_t<std::is_floating_point<T>::value>> {
|
1035 |
+
static constexpr auto name = _<std::is_same<T, float>::value
|
1036 |
+
|| std::is_same<T, const float>::value
|
1037 |
+
|| std::is_same<T, double>::value
|
1038 |
+
|| std::is_same<T, const double>::value>(
|
1039 |
+
_("numpy.float") + _<sizeof(T)*8>(), _("numpy.longdouble")
|
1040 |
+
);
|
1041 |
+
};
|
1042 |
+
|
1043 |
+
template <typename T>
|
1044 |
+
struct npy_format_descriptor_name<T, enable_if_t<is_complex<T>::value>> {
|
1045 |
+
static constexpr auto name = _<std::is_same<typename T::value_type, float>::value
|
1046 |
+
|| std::is_same<typename T::value_type, const float>::value
|
1047 |
+
|| std::is_same<typename T::value_type, double>::value
|
1048 |
+
|| std::is_same<typename T::value_type, const double>::value>(
|
1049 |
+
_("numpy.complex") + _<sizeof(typename T::value_type)*16>(), _("numpy.longcomplex")
|
1050 |
+
);
|
1051 |
+
};
|
1052 |
+
|
1053 |
+
template <typename T>
|
1054 |
+
struct npy_format_descriptor<T, enable_if_t<satisfies_any_of<T, std::is_arithmetic, is_complex>::value>>
|
1055 |
+
: npy_format_descriptor_name<T> {
|
1056 |
+
private:
|
1057 |
+
// NB: the order here must match the one in common.h
|
1058 |
+
constexpr static const int values[15] = {
|
1059 |
+
npy_api::NPY_BOOL_,
|
1060 |
+
npy_api::NPY_BYTE_, npy_api::NPY_UBYTE_, npy_api::NPY_INT16_, npy_api::NPY_UINT16_,
|
1061 |
+
npy_api::NPY_INT32_, npy_api::NPY_UINT32_, npy_api::NPY_INT64_, npy_api::NPY_UINT64_,
|
1062 |
+
npy_api::NPY_FLOAT_, npy_api::NPY_DOUBLE_, npy_api::NPY_LONGDOUBLE_,
|
1063 |
+
npy_api::NPY_CFLOAT_, npy_api::NPY_CDOUBLE_, npy_api::NPY_CLONGDOUBLE_
|
1064 |
+
};
|
1065 |
+
|
1066 |
+
public:
|
1067 |
+
static constexpr int value = values[detail::is_fmt_numeric<T>::index];
|
1068 |
+
|
1069 |
+
static pybind11::dtype dtype() {
|
1070 |
+
if (auto ptr = npy_api::get().PyArray_DescrFromType_(value))
|
1071 |
+
return reinterpret_steal<pybind11::dtype>(ptr);
|
1072 |
+
pybind11_fail("Unsupported buffer format!");
|
1073 |
+
}
|
1074 |
+
};
|
1075 |
+
|
1076 |
+
#define PYBIND11_DECL_CHAR_FMT \
|
1077 |
+
static constexpr auto name = _("S") + _<N>(); \
|
1078 |
+
static pybind11::dtype dtype() { return pybind11::dtype(std::string("S") + std::to_string(N)); }
|
1079 |
+
template <size_t N> struct npy_format_descriptor<char[N]> { PYBIND11_DECL_CHAR_FMT };
|
1080 |
+
template <size_t N> struct npy_format_descriptor<std::array<char, N>> { PYBIND11_DECL_CHAR_FMT };
|
1081 |
+
#undef PYBIND11_DECL_CHAR_FMT
|
1082 |
+
|
1083 |
+
template<typename T> struct npy_format_descriptor<T, enable_if_t<array_info<T>::is_array>> {
|
1084 |
+
private:
|
1085 |
+
using base_descr = npy_format_descriptor<typename array_info<T>::type>;
|
1086 |
+
public:
|
1087 |
+
static_assert(!array_info<T>::is_empty, "Zero-sized arrays are not supported");
|
1088 |
+
|
1089 |
+
static constexpr auto name = _("(") + array_info<T>::extents + _(")") + base_descr::name;
|
1090 |
+
static pybind11::dtype dtype() {
|
1091 |
+
list shape;
|
1092 |
+
array_info<T>::append_extents(shape);
|
1093 |
+
return pybind11::dtype::from_args(pybind11::make_tuple(base_descr::dtype(), shape));
|
1094 |
+
}
|
1095 |
+
};
|
1096 |
+
|
1097 |
+
template<typename T> struct npy_format_descriptor<T, enable_if_t<std::is_enum<T>::value>> {
|
1098 |
+
private:
|
1099 |
+
using base_descr = npy_format_descriptor<typename std::underlying_type<T>::type>;
|
1100 |
+
public:
|
1101 |
+
static constexpr auto name = base_descr::name;
|
1102 |
+
static pybind11::dtype dtype() { return base_descr::dtype(); }
|
1103 |
+
};
|
1104 |
+
|
1105 |
+
struct field_descriptor {
|
1106 |
+
const char *name;
|
1107 |
+
ssize_t offset;
|
1108 |
+
ssize_t size;
|
1109 |
+
std::string format;
|
1110 |
+
dtype descr;
|
1111 |
+
};
|
1112 |
+
|
1113 |
+
inline PYBIND11_NOINLINE void register_structured_dtype(
|
1114 |
+
any_container<field_descriptor> fields,
|
1115 |
+
const std::type_info& tinfo, ssize_t itemsize,
|
1116 |
+
bool (*direct_converter)(PyObject *, void *&)) {
|
1117 |
+
|
1118 |
+
auto& numpy_internals = get_numpy_internals();
|
1119 |
+
if (numpy_internals.get_type_info(tinfo, false))
|
1120 |
+
pybind11_fail("NumPy: dtype is already registered");
|
1121 |
+
|
1122 |
+
// Use ordered fields because order matters as of NumPy 1.14:
|
1123 |
+
// https://docs.scipy.org/doc/numpy/release.html#multiple-field-indexing-assignment-of-structured-arrays
|
1124 |
+
std::vector<field_descriptor> ordered_fields(std::move(fields));
|
1125 |
+
std::sort(ordered_fields.begin(), ordered_fields.end(),
|
1126 |
+
[](const field_descriptor &a, const field_descriptor &b) { return a.offset < b.offset; });
|
1127 |
+
|
1128 |
+
list names, formats, offsets;
|
1129 |
+
for (auto& field : ordered_fields) {
|
1130 |
+
if (!field.descr)
|
1131 |
+
pybind11_fail(std::string("NumPy: unsupported field dtype: `") +
|
1132 |
+
field.name + "` @ " + tinfo.name());
|
1133 |
+
names.append(PYBIND11_STR_TYPE(field.name));
|
1134 |
+
formats.append(field.descr);
|
1135 |
+
offsets.append(pybind11::int_(field.offset));
|
1136 |
+
}
|
1137 |
+
auto dtype_ptr = pybind11::dtype(names, formats, offsets, itemsize).release().ptr();
|
1138 |
+
|
1139 |
+
// There is an existing bug in NumPy (as of v1.11): trailing bytes are
|
1140 |
+
// not encoded explicitly into the format string. This will supposedly
|
1141 |
+
// get fixed in v1.12; for further details, see these:
|
1142 |
+
// - https://github.com/numpy/numpy/issues/7797
|
1143 |
+
// - https://github.com/numpy/numpy/pull/7798
|
1144 |
+
// Because of this, we won't use numpy's logic to generate buffer format
|
1145 |
+
// strings and will just do it ourselves.
|
1146 |
+
ssize_t offset = 0;
|
1147 |
+
std::ostringstream oss;
|
1148 |
+
// mark the structure as unaligned with '^', because numpy and C++ don't
|
1149 |
+
// always agree about alignment (particularly for complex), and we're
|
1150 |
+
// explicitly listing all our padding. This depends on none of the fields
|
1151 |
+
// overriding the endianness. Putting the ^ in front of individual fields
|
1152 |
+
// isn't guaranteed to work due to https://github.com/numpy/numpy/issues/9049
|
1153 |
+
oss << "^T{";
|
1154 |
+
for (auto& field : ordered_fields) {
|
1155 |
+
if (field.offset > offset)
|
1156 |
+
oss << (field.offset - offset) << 'x';
|
1157 |
+
oss << field.format << ':' << field.name << ':';
|
1158 |
+
offset = field.offset + field.size;
|
1159 |
+
}
|
1160 |
+
if (itemsize > offset)
|
1161 |
+
oss << (itemsize - offset) << 'x';
|
1162 |
+
oss << '}';
|
1163 |
+
auto format_str = oss.str();
|
1164 |
+
|
1165 |
+
// Sanity check: verify that NumPy properly parses our buffer format string
|
1166 |
+
auto& api = npy_api::get();
|
1167 |
+
auto arr = array(buffer_info(nullptr, itemsize, format_str, 1));
|
1168 |
+
if (!api.PyArray_EquivTypes_(dtype_ptr, arr.dtype().ptr()))
|
1169 |
+
pybind11_fail("NumPy: invalid buffer descriptor!");
|
1170 |
+
|
1171 |
+
auto tindex = std::type_index(tinfo);
|
1172 |
+
numpy_internals.registered_dtypes[tindex] = { dtype_ptr, format_str };
|
1173 |
+
get_internals().direct_conversions[tindex].push_back(direct_converter);
|
1174 |
+
}
|
1175 |
+
|
1176 |
+
template <typename T, typename SFINAE> struct npy_format_descriptor {
|
1177 |
+
static_assert(is_pod_struct<T>::value, "Attempt to use a non-POD or unimplemented POD type as a numpy dtype");
|
1178 |
+
|
1179 |
+
static constexpr auto name = make_caster<T>::name;
|
1180 |
+
|
1181 |
+
static pybind11::dtype dtype() {
|
1182 |
+
return reinterpret_borrow<pybind11::dtype>(dtype_ptr());
|
1183 |
+
}
|
1184 |
+
|
1185 |
+
static std::string format() {
|
1186 |
+
static auto format_str = get_numpy_internals().get_type_info<T>(true)->format_str;
|
1187 |
+
return format_str;
|
1188 |
+
}
|
1189 |
+
|
1190 |
+
static void register_dtype(any_container<field_descriptor> fields) {
|
1191 |
+
register_structured_dtype(std::move(fields), typeid(typename std::remove_cv<T>::type),
|
1192 |
+
sizeof(T), &direct_converter);
|
1193 |
+
}
|
1194 |
+
|
1195 |
+
private:
|
1196 |
+
static PyObject* dtype_ptr() {
|
1197 |
+
static PyObject* ptr = get_numpy_internals().get_type_info<T>(true)->dtype_ptr;
|
1198 |
+
return ptr;
|
1199 |
+
}
|
1200 |
+
|
1201 |
+
static bool direct_converter(PyObject *obj, void*& value) {
|
1202 |
+
auto& api = npy_api::get();
|
1203 |
+
if (!PyObject_TypeCheck(obj, api.PyVoidArrType_Type_))
|
1204 |
+
return false;
|
1205 |
+
if (auto descr = reinterpret_steal<object>(api.PyArray_DescrFromScalar_(obj))) {
|
1206 |
+
if (api.PyArray_EquivTypes_(dtype_ptr(), descr.ptr())) {
|
1207 |
+
value = ((PyVoidScalarObject_Proxy *) obj)->obval;
|
1208 |
+
return true;
|
1209 |
+
}
|
1210 |
+
}
|
1211 |
+
return false;
|
1212 |
+
}
|
1213 |
+
};
|
1214 |
+
|
1215 |
+
#ifdef __CLION_IDE__ // replace heavy macro with dummy code for the IDE (doesn't affect code)
|
1216 |
+
# define PYBIND11_NUMPY_DTYPE(Type, ...) ((void)0)
|
1217 |
+
# define PYBIND11_NUMPY_DTYPE_EX(Type, ...) ((void)0)
|
1218 |
+
#else
|
1219 |
+
|
1220 |
+
#define PYBIND11_FIELD_DESCRIPTOR_EX(T, Field, Name) \
|
1221 |
+
::pybind11::detail::field_descriptor { \
|
1222 |
+
Name, offsetof(T, Field), sizeof(decltype(std::declval<T>().Field)), \
|
1223 |
+
::pybind11::format_descriptor<decltype(std::declval<T>().Field)>::format(), \
|
1224 |
+
::pybind11::detail::npy_format_descriptor<decltype(std::declval<T>().Field)>::dtype() \
|
1225 |
+
}
|
1226 |
+
|
1227 |
+
// Extract name, offset and format descriptor for a struct field
|
1228 |
+
#define PYBIND11_FIELD_DESCRIPTOR(T, Field) PYBIND11_FIELD_DESCRIPTOR_EX(T, Field, #Field)
|
1229 |
+
|
1230 |
+
// The main idea of this macro is borrowed from https://github.com/swansontec/map-macro
|
1231 |
+
// (C) William Swanson, Paul Fultz
|
1232 |
+
#define PYBIND11_EVAL0(...) __VA_ARGS__
|
1233 |
+
#define PYBIND11_EVAL1(...) PYBIND11_EVAL0 (PYBIND11_EVAL0 (PYBIND11_EVAL0 (__VA_ARGS__)))
|
1234 |
+
#define PYBIND11_EVAL2(...) PYBIND11_EVAL1 (PYBIND11_EVAL1 (PYBIND11_EVAL1 (__VA_ARGS__)))
|
1235 |
+
#define PYBIND11_EVAL3(...) PYBIND11_EVAL2 (PYBIND11_EVAL2 (PYBIND11_EVAL2 (__VA_ARGS__)))
|
1236 |
+
#define PYBIND11_EVAL4(...) PYBIND11_EVAL3 (PYBIND11_EVAL3 (PYBIND11_EVAL3 (__VA_ARGS__)))
|
1237 |
+
#define PYBIND11_EVAL(...) PYBIND11_EVAL4 (PYBIND11_EVAL4 (PYBIND11_EVAL4 (__VA_ARGS__)))
|
1238 |
+
#define PYBIND11_MAP_END(...)
|
1239 |
+
#define PYBIND11_MAP_OUT
|
1240 |
+
#define PYBIND11_MAP_COMMA ,
|
1241 |
+
#define PYBIND11_MAP_GET_END() 0, PYBIND11_MAP_END
|
1242 |
+
#define PYBIND11_MAP_NEXT0(test, next, ...) next PYBIND11_MAP_OUT
|
1243 |
+
#define PYBIND11_MAP_NEXT1(test, next) PYBIND11_MAP_NEXT0 (test, next, 0)
|
1244 |
+
#define PYBIND11_MAP_NEXT(test, next) PYBIND11_MAP_NEXT1 (PYBIND11_MAP_GET_END test, next)
|
1245 |
+
#if defined(_MSC_VER) && !defined(__clang__) // MSVC is not as eager to expand macros, hence this workaround
|
1246 |
+
#define PYBIND11_MAP_LIST_NEXT1(test, next) \
|
1247 |
+
PYBIND11_EVAL0 (PYBIND11_MAP_NEXT0 (test, PYBIND11_MAP_COMMA next, 0))
|
1248 |
+
#else
|
1249 |
+
#define PYBIND11_MAP_LIST_NEXT1(test, next) \
|
1250 |
+
PYBIND11_MAP_NEXT0 (test, PYBIND11_MAP_COMMA next, 0)
|
1251 |
+
#endif
|
1252 |
+
#define PYBIND11_MAP_LIST_NEXT(test, next) \
|
1253 |
+
PYBIND11_MAP_LIST_NEXT1 (PYBIND11_MAP_GET_END test, next)
|
1254 |
+
#define PYBIND11_MAP_LIST0(f, t, x, peek, ...) \
|
1255 |
+
f(t, x) PYBIND11_MAP_LIST_NEXT (peek, PYBIND11_MAP_LIST1) (f, t, peek, __VA_ARGS__)
|
1256 |
+
#define PYBIND11_MAP_LIST1(f, t, x, peek, ...) \
|
1257 |
+
f(t, x) PYBIND11_MAP_LIST_NEXT (peek, PYBIND11_MAP_LIST0) (f, t, peek, __VA_ARGS__)
|
1258 |
+
// PYBIND11_MAP_LIST(f, t, a1, a2, ...) expands to f(t, a1), f(t, a2), ...
|
1259 |
+
#define PYBIND11_MAP_LIST(f, t, ...) \
|
1260 |
+
PYBIND11_EVAL (PYBIND11_MAP_LIST1 (f, t, __VA_ARGS__, (), 0))
|
1261 |
+
|
1262 |
+
#define PYBIND11_NUMPY_DTYPE(Type, ...) \
|
1263 |
+
::pybind11::detail::npy_format_descriptor<Type>::register_dtype \
|
1264 |
+
(::std::vector<::pybind11::detail::field_descriptor> \
|
1265 |
+
{PYBIND11_MAP_LIST (PYBIND11_FIELD_DESCRIPTOR, Type, __VA_ARGS__)})
|
1266 |
+
|
1267 |
+
#if defined(_MSC_VER) && !defined(__clang__)
|
1268 |
+
#define PYBIND11_MAP2_LIST_NEXT1(test, next) \
|
1269 |
+
PYBIND11_EVAL0 (PYBIND11_MAP_NEXT0 (test, PYBIND11_MAP_COMMA next, 0))
|
1270 |
+
#else
|
1271 |
+
#define PYBIND11_MAP2_LIST_NEXT1(test, next) \
|
1272 |
+
PYBIND11_MAP_NEXT0 (test, PYBIND11_MAP_COMMA next, 0)
|
1273 |
+
#endif
|
1274 |
+
#define PYBIND11_MAP2_LIST_NEXT(test, next) \
|
1275 |
+
PYBIND11_MAP2_LIST_NEXT1 (PYBIND11_MAP_GET_END test, next)
|
1276 |
+
#define PYBIND11_MAP2_LIST0(f, t, x1, x2, peek, ...) \
|
1277 |
+
f(t, x1, x2) PYBIND11_MAP2_LIST_NEXT (peek, PYBIND11_MAP2_LIST1) (f, t, peek, __VA_ARGS__)
|
1278 |
+
#define PYBIND11_MAP2_LIST1(f, t, x1, x2, peek, ...) \
|
1279 |
+
f(t, x1, x2) PYBIND11_MAP2_LIST_NEXT (peek, PYBIND11_MAP2_LIST0) (f, t, peek, __VA_ARGS__)
|
1280 |
+
// PYBIND11_MAP2_LIST(f, t, a1, a2, ...) expands to f(t, a1, a2), f(t, a3, a4), ...
|
1281 |
+
#define PYBIND11_MAP2_LIST(f, t, ...) \
|
1282 |
+
PYBIND11_EVAL (PYBIND11_MAP2_LIST1 (f, t, __VA_ARGS__, (), 0))
|
1283 |
+
|
1284 |
+
#define PYBIND11_NUMPY_DTYPE_EX(Type, ...) \
|
1285 |
+
::pybind11::detail::npy_format_descriptor<Type>::register_dtype \
|
1286 |
+
(::std::vector<::pybind11::detail::field_descriptor> \
|
1287 |
+
{PYBIND11_MAP2_LIST (PYBIND11_FIELD_DESCRIPTOR_EX, Type, __VA_ARGS__)})
|
1288 |
+
|
1289 |
+
#endif // __CLION_IDE__
|
1290 |
+
|
1291 |
+
class common_iterator {
|
1292 |
+
public:
|
1293 |
+
using container_type = std::vector<ssize_t>;
|
1294 |
+
using value_type = container_type::value_type;
|
1295 |
+
using size_type = container_type::size_type;
|
1296 |
+
|
1297 |
+
common_iterator() : m_strides() {}
|
1298 |
+
|
1299 |
+
common_iterator(void* ptr, const container_type& strides, const container_type& shape)
|
1300 |
+
: p_ptr(reinterpret_cast<char*>(ptr)), m_strides(strides.size()) {
|
1301 |
+
m_strides.back() = static_cast<value_type>(strides.back());
|
1302 |
+
for (size_type i = m_strides.size() - 1; i != 0; --i) {
|
1303 |
+
size_type j = i - 1;
|
1304 |
+
auto s = static_cast<value_type>(shape[i]);
|
1305 |
+
m_strides[j] = strides[j] + m_strides[i] - strides[i] * s;
|
1306 |
+
}
|
1307 |
+
}
|
1308 |
+
|
1309 |
+
void increment(size_type dim) {
|
1310 |
+
p_ptr += m_strides[dim];
|
1311 |
+
}
|
1312 |
+
|
1313 |
+
void* data() const {
|
1314 |
+
return p_ptr;
|
1315 |
+
}
|
1316 |
+
|
1317 |
+
private:
|
1318 |
+
char *p_ptr{0};
|
1319 |
+
container_type m_strides;
|
1320 |
+
};
|
1321 |
+
|
1322 |
+
template <size_t N> class multi_array_iterator {
|
1323 |
+
public:
|
1324 |
+
using container_type = std::vector<ssize_t>;
|
1325 |
+
|
1326 |
+
multi_array_iterator(const std::array<buffer_info, N> &buffers,
|
1327 |
+
const container_type &shape)
|
1328 |
+
: m_shape(shape.size()), m_index(shape.size(), 0),
|
1329 |
+
m_common_iterator() {
|
1330 |
+
|
1331 |
+
// Manual copy to avoid conversion warning if using std::copy
|
1332 |
+
for (size_t i = 0; i < shape.size(); ++i)
|
1333 |
+
m_shape[i] = shape[i];
|
1334 |
+
|
1335 |
+
container_type strides(shape.size());
|
1336 |
+
for (size_t i = 0; i < N; ++i)
|
1337 |
+
init_common_iterator(buffers[i], shape, m_common_iterator[i], strides);
|
1338 |
+
}
|
1339 |
+
|
1340 |
+
multi_array_iterator& operator++() {
|
1341 |
+
for (size_t j = m_index.size(); j != 0; --j) {
|
1342 |
+
size_t i = j - 1;
|
1343 |
+
if (++m_index[i] != m_shape[i]) {
|
1344 |
+
increment_common_iterator(i);
|
1345 |
+
break;
|
1346 |
+
}
|
1347 |
+
m_index[i] = 0;
|
1348 |
+
}
|
1349 |
+
return *this;
|
1350 |
+
}
|
1351 |
+
|
1352 |
+
template <size_t K, class T = void> T* data() const {
|
1353 |
+
return reinterpret_cast<T*>(m_common_iterator[K].data());
|
1354 |
+
}
|
1355 |
+
|
1356 |
+
private:
|
1357 |
+
|
1358 |
+
using common_iter = common_iterator;
|
1359 |
+
|
1360 |
+
void init_common_iterator(const buffer_info &buffer,
|
1361 |
+
const container_type &shape,
|
1362 |
+
common_iter &iterator,
|
1363 |
+
container_type &strides) {
|
1364 |
+
auto buffer_shape_iter = buffer.shape.rbegin();
|
1365 |
+
auto buffer_strides_iter = buffer.strides.rbegin();
|
1366 |
+
auto shape_iter = shape.rbegin();
|
1367 |
+
auto strides_iter = strides.rbegin();
|
1368 |
+
|
1369 |
+
while (buffer_shape_iter != buffer.shape.rend()) {
|
1370 |
+
if (*shape_iter == *buffer_shape_iter)
|
1371 |
+
*strides_iter = *buffer_strides_iter;
|
1372 |
+
else
|
1373 |
+
*strides_iter = 0;
|
1374 |
+
|
1375 |
+
++buffer_shape_iter;
|
1376 |
+
++buffer_strides_iter;
|
1377 |
+
++shape_iter;
|
1378 |
+
++strides_iter;
|
1379 |
+
}
|
1380 |
+
|
1381 |
+
std::fill(strides_iter, strides.rend(), 0);
|
1382 |
+
iterator = common_iter(buffer.ptr, strides, shape);
|
1383 |
+
}
|
1384 |
+
|
1385 |
+
void increment_common_iterator(size_t dim) {
|
1386 |
+
for (auto &iter : m_common_iterator)
|
1387 |
+
iter.increment(dim);
|
1388 |
+
}
|
1389 |
+
|
1390 |
+
container_type m_shape;
|
1391 |
+
container_type m_index;
|
1392 |
+
std::array<common_iter, N> m_common_iterator;
|
1393 |
+
};
|
1394 |
+
|
1395 |
+
enum class broadcast_trivial { non_trivial, c_trivial, f_trivial };
|
1396 |
+
|
1397 |
+
// Populates the shape and number of dimensions for the set of buffers. Returns a broadcast_trivial
|
1398 |
+
// enum value indicating whether the broadcast is "trivial"--that is, has each buffer being either a
|
1399 |
+
// singleton or a full-size, C-contiguous (`c_trivial`) or Fortran-contiguous (`f_trivial`) storage
|
1400 |
+
// buffer; returns `non_trivial` otherwise.
|
1401 |
+
template <size_t N>
|
1402 |
+
broadcast_trivial broadcast(const std::array<buffer_info, N> &buffers, ssize_t &ndim, std::vector<ssize_t> &shape) {
|
1403 |
+
ndim = std::accumulate(buffers.begin(), buffers.end(), ssize_t(0), [](ssize_t res, const buffer_info &buf) {
|
1404 |
+
return std::max(res, buf.ndim);
|
1405 |
+
});
|
1406 |
+
|
1407 |
+
shape.clear();
|
1408 |
+
shape.resize((size_t) ndim, 1);
|
1409 |
+
|
1410 |
+
// Figure out the output size, and make sure all input arrays conform (i.e. are either size 1 or
|
1411 |
+
// the full size).
|
1412 |
+
for (size_t i = 0; i < N; ++i) {
|
1413 |
+
auto res_iter = shape.rbegin();
|
1414 |
+
auto end = buffers[i].shape.rend();
|
1415 |
+
for (auto shape_iter = buffers[i].shape.rbegin(); shape_iter != end; ++shape_iter, ++res_iter) {
|
1416 |
+
const auto &dim_size_in = *shape_iter;
|
1417 |
+
auto &dim_size_out = *res_iter;
|
1418 |
+
|
1419 |
+
// Each input dimension can either be 1 or `n`, but `n` values must match across buffers
|
1420 |
+
if (dim_size_out == 1)
|
1421 |
+
dim_size_out = dim_size_in;
|
1422 |
+
else if (dim_size_in != 1 && dim_size_in != dim_size_out)
|
1423 |
+
pybind11_fail("pybind11::vectorize: incompatible size/dimension of inputs!");
|
1424 |
+
}
|
1425 |
+
}
|
1426 |
+
|
1427 |
+
bool trivial_broadcast_c = true;
|
1428 |
+
bool trivial_broadcast_f = true;
|
1429 |
+
for (size_t i = 0; i < N && (trivial_broadcast_c || trivial_broadcast_f); ++i) {
|
1430 |
+
if (buffers[i].size == 1)
|
1431 |
+
continue;
|
1432 |
+
|
1433 |
+
// Require the same number of dimensions:
|
1434 |
+
if (buffers[i].ndim != ndim)
|
1435 |
+
return broadcast_trivial::non_trivial;
|
1436 |
+
|
1437 |
+
// Require all dimensions be full-size:
|
1438 |
+
if (!std::equal(buffers[i].shape.cbegin(), buffers[i].shape.cend(), shape.cbegin()))
|
1439 |
+
return broadcast_trivial::non_trivial;
|
1440 |
+
|
1441 |
+
// Check for C contiguity (but only if previous inputs were also C contiguous)
|
1442 |
+
if (trivial_broadcast_c) {
|
1443 |
+
ssize_t expect_stride = buffers[i].itemsize;
|
1444 |
+
auto end = buffers[i].shape.crend();
|
1445 |
+
for (auto shape_iter = buffers[i].shape.crbegin(), stride_iter = buffers[i].strides.crbegin();
|
1446 |
+
trivial_broadcast_c && shape_iter != end; ++shape_iter, ++stride_iter) {
|
1447 |
+
if (expect_stride == *stride_iter)
|
1448 |
+
expect_stride *= *shape_iter;
|
1449 |
+
else
|
1450 |
+
trivial_broadcast_c = false;
|
1451 |
+
}
|
1452 |
+
}
|
1453 |
+
|
1454 |
+
// Check for Fortran contiguity (if previous inputs were also F contiguous)
|
1455 |
+
if (trivial_broadcast_f) {
|
1456 |
+
ssize_t expect_stride = buffers[i].itemsize;
|
1457 |
+
auto end = buffers[i].shape.cend();
|
1458 |
+
for (auto shape_iter = buffers[i].shape.cbegin(), stride_iter = buffers[i].strides.cbegin();
|
1459 |
+
trivial_broadcast_f && shape_iter != end; ++shape_iter, ++stride_iter) {
|
1460 |
+
if (expect_stride == *stride_iter)
|
1461 |
+
expect_stride *= *shape_iter;
|
1462 |
+
else
|
1463 |
+
trivial_broadcast_f = false;
|
1464 |
+
}
|
1465 |
+
}
|
1466 |
+
}
|
1467 |
+
|
1468 |
+
return
|
1469 |
+
trivial_broadcast_c ? broadcast_trivial::c_trivial :
|
1470 |
+
trivial_broadcast_f ? broadcast_trivial::f_trivial :
|
1471 |
+
broadcast_trivial::non_trivial;
|
1472 |
+
}
|
1473 |
+
|
1474 |
+
template <typename T>
|
1475 |
+
struct vectorize_arg {
|
1476 |
+
static_assert(!std::is_rvalue_reference<T>::value, "Functions with rvalue reference arguments cannot be vectorized");
|
1477 |
+
// The wrapped function gets called with this type:
|
1478 |
+
using call_type = remove_reference_t<T>;
|
1479 |
+
// Is this a vectorized argument?
|
1480 |
+
static constexpr bool vectorize =
|
1481 |
+
satisfies_any_of<call_type, std::is_arithmetic, is_complex, is_pod>::value &&
|
1482 |
+
satisfies_none_of<call_type, std::is_pointer, std::is_array, is_std_array, std::is_enum>::value &&
|
1483 |
+
(!std::is_reference<T>::value ||
|
1484 |
+
(std::is_lvalue_reference<T>::value && std::is_const<call_type>::value));
|
1485 |
+
// Accept this type: an array for vectorized types, otherwise the type as-is:
|
1486 |
+
using type = conditional_t<vectorize, array_t<remove_cv_t<call_type>, array::forcecast>, T>;
|
1487 |
+
};
|
1488 |
+
|
1489 |
+
|
1490 |
+
// py::vectorize when a return type is present
|
1491 |
+
template <typename Func, typename Return, typename... Args>
|
1492 |
+
struct vectorize_returned_array {
|
1493 |
+
using Type = array_t<Return>;
|
1494 |
+
|
1495 |
+
static Type create(broadcast_trivial trivial, const std::vector<ssize_t> &shape) {
|
1496 |
+
if (trivial == broadcast_trivial::f_trivial)
|
1497 |
+
return array_t<Return, array::f_style>(shape);
|
1498 |
+
return array_t<Return>(shape);
|
1499 |
+
}
|
1500 |
+
|
1501 |
+
static Return *mutable_data(Type &array) {
|
1502 |
+
return array.mutable_data();
|
1503 |
+
}
|
1504 |
+
|
1505 |
+
static Return call(Func &f, Args &... args) {
|
1506 |
+
return f(args...);
|
1507 |
+
}
|
1508 |
+
|
1509 |
+
static void call(Return *out, size_t i, Func &f, Args &... args) {
|
1510 |
+
out[i] = f(args...);
|
1511 |
+
}
|
1512 |
+
};
|
1513 |
+
|
1514 |
+
// py::vectorize when a return type is not present
|
1515 |
+
template <typename Func, typename... Args>
|
1516 |
+
struct vectorize_returned_array<Func, void, Args...> {
|
1517 |
+
using Type = none;
|
1518 |
+
|
1519 |
+
static Type create(broadcast_trivial, const std::vector<ssize_t> &) {
|
1520 |
+
return none();
|
1521 |
+
}
|
1522 |
+
|
1523 |
+
static void *mutable_data(Type &) {
|
1524 |
+
return nullptr;
|
1525 |
+
}
|
1526 |
+
|
1527 |
+
static detail::void_type call(Func &f, Args &... args) {
|
1528 |
+
f(args...);
|
1529 |
+
return {};
|
1530 |
+
}
|
1531 |
+
|
1532 |
+
static void call(void *, size_t, Func &f, Args &... args) {
|
1533 |
+
f(args...);
|
1534 |
+
}
|
1535 |
+
};
|
1536 |
+
|
1537 |
+
|
1538 |
+
template <typename Func, typename Return, typename... Args>
|
1539 |
+
struct vectorize_helper {
|
1540 |
+
|
1541 |
+
// NVCC for some reason breaks if NVectorized is private
|
1542 |
+
#ifdef __CUDACC__
|
1543 |
+
public:
|
1544 |
+
#else
|
1545 |
+
private:
|
1546 |
+
#endif
|
1547 |
+
|
1548 |
+
static constexpr size_t N = sizeof...(Args);
|
1549 |
+
static constexpr size_t NVectorized = constexpr_sum(vectorize_arg<Args>::vectorize...);
|
1550 |
+
static_assert(NVectorized >= 1,
|
1551 |
+
"pybind11::vectorize(...) requires a function with at least one vectorizable argument");
|
1552 |
+
|
1553 |
+
public:
|
1554 |
+
template <typename T>
|
1555 |
+
explicit vectorize_helper(T &&f) : f(std::forward<T>(f)) { }
|
1556 |
+
|
1557 |
+
object operator()(typename vectorize_arg<Args>::type... args) {
|
1558 |
+
return run(args...,
|
1559 |
+
make_index_sequence<N>(),
|
1560 |
+
select_indices<vectorize_arg<Args>::vectorize...>(),
|
1561 |
+
make_index_sequence<NVectorized>());
|
1562 |
+
}
|
1563 |
+
|
1564 |
+
private:
|
1565 |
+
remove_reference_t<Func> f;
|
1566 |
+
|
1567 |
+
// Internal compiler error in MSVC 19.16.27025.1 (Visual Studio 2017 15.9.4), when compiling with "/permissive-" flag
|
1568 |
+
// when arg_call_types is manually inlined.
|
1569 |
+
using arg_call_types = std::tuple<typename vectorize_arg<Args>::call_type...>;
|
1570 |
+
template <size_t Index> using param_n_t = typename std::tuple_element<Index, arg_call_types>::type;
|
1571 |
+
|
1572 |
+
using returned_array = vectorize_returned_array<Func, Return, Args...>;
|
1573 |
+
|
1574 |
+
// Runs a vectorized function given arguments tuple and three index sequences:
|
1575 |
+
// - Index is the full set of 0 ... (N-1) argument indices;
|
1576 |
+
// - VIndex is the subset of argument indices with vectorized parameters, letting us access
|
1577 |
+
// vectorized arguments (anything not in this sequence is passed through)
|
1578 |
+
// - BIndex is a incremental sequence (beginning at 0) of the same size as VIndex, so that
|
1579 |
+
// we can store vectorized buffer_infos in an array (argument VIndex has its buffer at
|
1580 |
+
// index BIndex in the array).
|
1581 |
+
template <size_t... Index, size_t... VIndex, size_t... BIndex> object run(
|
1582 |
+
typename vectorize_arg<Args>::type &...args,
|
1583 |
+
index_sequence<Index...> i_seq, index_sequence<VIndex...> vi_seq, index_sequence<BIndex...> bi_seq) {
|
1584 |
+
|
1585 |
+
// Pointers to values the function was called with; the vectorized ones set here will start
|
1586 |
+
// out as array_t<T> pointers, but they will be changed them to T pointers before we make
|
1587 |
+
// call the wrapped function. Non-vectorized pointers are left as-is.
|
1588 |
+
std::array<void *, N> params{{ &args... }};
|
1589 |
+
|
1590 |
+
// The array of `buffer_info`s of vectorized arguments:
|
1591 |
+
std::array<buffer_info, NVectorized> buffers{{ reinterpret_cast<array *>(params[VIndex])->request()... }};
|
1592 |
+
|
1593 |
+
/* Determine dimensions parameters of output array */
|
1594 |
+
ssize_t nd = 0;
|
1595 |
+
std::vector<ssize_t> shape(0);
|
1596 |
+
auto trivial = broadcast(buffers, nd, shape);
|
1597 |
+
auto ndim = (size_t) nd;
|
1598 |
+
|
1599 |
+
size_t size = std::accumulate(shape.begin(), shape.end(), (size_t) 1, std::multiplies<size_t>());
|
1600 |
+
|
1601 |
+
// If all arguments are 0-dimension arrays (i.e. single values) return a plain value (i.e.
|
1602 |
+
// not wrapped in an array).
|
1603 |
+
if (size == 1 && ndim == 0) {
|
1604 |
+
PYBIND11_EXPAND_SIDE_EFFECTS(params[VIndex] = buffers[BIndex].ptr);
|
1605 |
+
return cast(returned_array::call(f, *reinterpret_cast<param_n_t<Index> *>(params[Index])...));
|
1606 |
+
}
|
1607 |
+
|
1608 |
+
auto result = returned_array::create(trivial, shape);
|
1609 |
+
|
1610 |
+
if (size == 0) return std::move(result);
|
1611 |
+
|
1612 |
+
/* Call the function */
|
1613 |
+
auto mutable_data = returned_array::mutable_data(result);
|
1614 |
+
if (trivial == broadcast_trivial::non_trivial)
|
1615 |
+
apply_broadcast(buffers, params, mutable_data, size, shape, i_seq, vi_seq, bi_seq);
|
1616 |
+
else
|
1617 |
+
apply_trivial(buffers, params, mutable_data, size, i_seq, vi_seq, bi_seq);
|
1618 |
+
|
1619 |
+
return std::move(result);
|
1620 |
+
}
|
1621 |
+
|
1622 |
+
template <size_t... Index, size_t... VIndex, size_t... BIndex>
|
1623 |
+
void apply_trivial(std::array<buffer_info, NVectorized> &buffers,
|
1624 |
+
std::array<void *, N> ¶ms,
|
1625 |
+
Return *out,
|
1626 |
+
size_t size,
|
1627 |
+
index_sequence<Index...>, index_sequence<VIndex...>, index_sequence<BIndex...>) {
|
1628 |
+
|
1629 |
+
// Initialize an array of mutable byte references and sizes with references set to the
|
1630 |
+
// appropriate pointer in `params`; as we iterate, we'll increment each pointer by its size
|
1631 |
+
// (except for singletons, which get an increment of 0).
|
1632 |
+
std::array<std::pair<unsigned char *&, const size_t>, NVectorized> vecparams{{
|
1633 |
+
std::pair<unsigned char *&, const size_t>(
|
1634 |
+
reinterpret_cast<unsigned char *&>(params[VIndex] = buffers[BIndex].ptr),
|
1635 |
+
buffers[BIndex].size == 1 ? 0 : sizeof(param_n_t<VIndex>)
|
1636 |
+
)...
|
1637 |
+
}};
|
1638 |
+
|
1639 |
+
for (size_t i = 0; i < size; ++i) {
|
1640 |
+
returned_array::call(out, i, f, *reinterpret_cast<param_n_t<Index> *>(params[Index])...);
|
1641 |
+
for (auto &x : vecparams) x.first += x.second;
|
1642 |
+
}
|
1643 |
+
}
|
1644 |
+
|
1645 |
+
template <size_t... Index, size_t... VIndex, size_t... BIndex>
|
1646 |
+
void apply_broadcast(std::array<buffer_info, NVectorized> &buffers,
|
1647 |
+
std::array<void *, N> ¶ms,
|
1648 |
+
Return *out,
|
1649 |
+
size_t size,
|
1650 |
+
const std::vector<ssize_t> &output_shape,
|
1651 |
+
index_sequence<Index...>, index_sequence<VIndex...>, index_sequence<BIndex...>) {
|
1652 |
+
|
1653 |
+
multi_array_iterator<NVectorized> input_iter(buffers, output_shape);
|
1654 |
+
|
1655 |
+
for (size_t i = 0; i < size; ++i, ++input_iter) {
|
1656 |
+
PYBIND11_EXPAND_SIDE_EFFECTS((
|
1657 |
+
params[VIndex] = input_iter.template data<BIndex>()
|
1658 |
+
));
|
1659 |
+
returned_array::call(out, i, f, *reinterpret_cast<param_n_t<Index> *>(std::get<Index>(params))...);
|
1660 |
+
}
|
1661 |
+
}
|
1662 |
+
};
|
1663 |
+
|
1664 |
+
template <typename Func, typename Return, typename... Args>
|
1665 |
+
vectorize_helper<Func, Return, Args...>
|
1666 |
+
vectorize_extractor(const Func &f, Return (*) (Args ...)) {
|
1667 |
+
return detail::vectorize_helper<Func, Return, Args...>(f);
|
1668 |
+
}
|
1669 |
+
|
1670 |
+
template <typename T, int Flags> struct handle_type_name<array_t<T, Flags>> {
|
1671 |
+
static constexpr auto name = _("numpy.ndarray[") + npy_format_descriptor<T>::name + _("]");
|
1672 |
+
};
|
1673 |
+
|
1674 |
+
PYBIND11_NAMESPACE_END(detail)
|
1675 |
+
|
1676 |
+
// Vanilla pointer vectorizer:
|
1677 |
+
template <typename Return, typename... Args>
|
1678 |
+
detail::vectorize_helper<Return (*)(Args...), Return, Args...>
|
1679 |
+
vectorize(Return (*f) (Args ...)) {
|
1680 |
+
return detail::vectorize_helper<Return (*)(Args...), Return, Args...>(f);
|
1681 |
+
}
|
1682 |
+
|
1683 |
+
// lambda vectorizer:
|
1684 |
+
template <typename Func, detail::enable_if_t<detail::is_lambda<Func>::value, int> = 0>
|
1685 |
+
auto vectorize(Func &&f) -> decltype(
|
1686 |
+
detail::vectorize_extractor(std::forward<Func>(f), (detail::function_signature_t<Func> *) nullptr)) {
|
1687 |
+
return detail::vectorize_extractor(std::forward<Func>(f), (detail::function_signature_t<Func> *) nullptr);
|
1688 |
+
}
|
1689 |
+
|
1690 |
+
// Vectorize a class method (non-const):
|
1691 |
+
template <typename Return, typename Class, typename... Args,
|
1692 |
+
typename Helper = detail::vectorize_helper<decltype(std::mem_fn(std::declval<Return (Class::*)(Args...)>())), Return, Class *, Args...>>
|
1693 |
+
Helper vectorize(Return (Class::*f)(Args...)) {
|
1694 |
+
return Helper(std::mem_fn(f));
|
1695 |
+
}
|
1696 |
+
|
1697 |
+
// Vectorize a class method (const):
|
1698 |
+
template <typename Return, typename Class, typename... Args,
|
1699 |
+
typename Helper = detail::vectorize_helper<decltype(std::mem_fn(std::declval<Return (Class::*)(Args...) const>())), Return, const Class *, Args...>>
|
1700 |
+
Helper vectorize(Return (Class::*f)(Args...) const) {
|
1701 |
+
return Helper(std::mem_fn(f));
|
1702 |
+
}
|
1703 |
+
|
1704 |
+
PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)
|
1705 |
+
|
1706 |
+
#if defined(_MSC_VER)
|
1707 |
+
#pragma warning(pop)
|
1708 |
+
#endif
|
third-party/DPVO/Pangolin/components/pango_python/pybind11/include/pybind11/operators.h
ADDED
@@ -0,0 +1,173 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/*
|
2 |
+
pybind11/operator.h: Metatemplates for operator overloading
|
3 |
+
|
4 |
+
Copyright (c) 2016 Wenzel Jakob <[email protected]>
|
5 |
+
|
6 |
+
All rights reserved. Use of this source code is governed by a
|
7 |
+
BSD-style license that can be found in the LICENSE file.
|
8 |
+
*/
|
9 |
+
|
10 |
+
#pragma once
|
11 |
+
|
12 |
+
#include "pybind11.h"
|
13 |
+
|
14 |
+
#if defined(__clang__) && !defined(__INTEL_COMPILER)
|
15 |
+
# pragma clang diagnostic ignored "-Wunsequenced" // multiple unsequenced modifications to 'self' (when using def(py::self OP Type()))
|
16 |
+
#elif defined(_MSC_VER)
|
17 |
+
# pragma warning(push)
|
18 |
+
# pragma warning(disable: 4127) // warning C4127: Conditional expression is constant
|
19 |
+
#endif
|
20 |
+
|
21 |
+
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
|
22 |
+
PYBIND11_NAMESPACE_BEGIN(detail)
|
23 |
+
|
24 |
+
/// Enumeration with all supported operator types
|
25 |
+
enum op_id : int {
|
26 |
+
op_add, op_sub, op_mul, op_div, op_mod, op_divmod, op_pow, op_lshift,
|
27 |
+
op_rshift, op_and, op_xor, op_or, op_neg, op_pos, op_abs, op_invert,
|
28 |
+
op_int, op_long, op_float, op_str, op_cmp, op_gt, op_ge, op_lt, op_le,
|
29 |
+
op_eq, op_ne, op_iadd, op_isub, op_imul, op_idiv, op_imod, op_ilshift,
|
30 |
+
op_irshift, op_iand, op_ixor, op_ior, op_complex, op_bool, op_nonzero,
|
31 |
+
op_repr, op_truediv, op_itruediv, op_hash
|
32 |
+
};
|
33 |
+
|
34 |
+
enum op_type : int {
|
35 |
+
op_l, /* base type on left */
|
36 |
+
op_r, /* base type on right */
|
37 |
+
op_u /* unary operator */
|
38 |
+
};
|
39 |
+
|
40 |
+
struct self_t { };
|
41 |
+
static const self_t self = self_t();
|
42 |
+
|
43 |
+
/// Type for an unused type slot
|
44 |
+
struct undefined_t { };
|
45 |
+
|
46 |
+
/// Don't warn about an unused variable
|
47 |
+
inline self_t __self() { return self; }
|
48 |
+
|
49 |
+
/// base template of operator implementations
|
50 |
+
template <op_id, op_type, typename B, typename L, typename R> struct op_impl { };
|
51 |
+
|
52 |
+
/// Operator implementation generator
|
53 |
+
template <op_id id, op_type ot, typename L, typename R> struct op_ {
|
54 |
+
template <typename Class, typename... Extra> void execute(Class &cl, const Extra&... extra) const {
|
55 |
+
using Base = typename Class::type;
|
56 |
+
using L_type = conditional_t<std::is_same<L, self_t>::value, Base, L>;
|
57 |
+
using R_type = conditional_t<std::is_same<R, self_t>::value, Base, R>;
|
58 |
+
using op = op_impl<id, ot, Base, L_type, R_type>;
|
59 |
+
cl.def(op::name(), &op::execute, is_operator(), extra...);
|
60 |
+
#if PY_MAJOR_VERSION < 3
|
61 |
+
if (id == op_truediv || id == op_itruediv)
|
62 |
+
cl.def(id == op_itruediv ? "__idiv__" : ot == op_l ? "__div__" : "__rdiv__",
|
63 |
+
&op::execute, is_operator(), extra...);
|
64 |
+
#endif
|
65 |
+
}
|
66 |
+
template <typename Class, typename... Extra> void execute_cast(Class &cl, const Extra&... extra) const {
|
67 |
+
using Base = typename Class::type;
|
68 |
+
using L_type = conditional_t<std::is_same<L, self_t>::value, Base, L>;
|
69 |
+
using R_type = conditional_t<std::is_same<R, self_t>::value, Base, R>;
|
70 |
+
using op = op_impl<id, ot, Base, L_type, R_type>;
|
71 |
+
cl.def(op::name(), &op::execute_cast, is_operator(), extra...);
|
72 |
+
#if PY_MAJOR_VERSION < 3
|
73 |
+
if (id == op_truediv || id == op_itruediv)
|
74 |
+
cl.def(id == op_itruediv ? "__idiv__" : ot == op_l ? "__div__" : "__rdiv__",
|
75 |
+
&op::execute, is_operator(), extra...);
|
76 |
+
#endif
|
77 |
+
}
|
78 |
+
};
|
79 |
+
|
80 |
+
#define PYBIND11_BINARY_OPERATOR(id, rid, op, expr) \
|
81 |
+
template <typename B, typename L, typename R> struct op_impl<op_##id, op_l, B, L, R> { \
|
82 |
+
static char const* name() { return "__" #id "__"; } \
|
83 |
+
static auto execute(const L &l, const R &r) -> decltype(expr) { return (expr); } \
|
84 |
+
static B execute_cast(const L &l, const R &r) { return B(expr); } \
|
85 |
+
}; \
|
86 |
+
template <typename B, typename L, typename R> struct op_impl<op_##id, op_r, B, L, R> { \
|
87 |
+
static char const* name() { return "__" #rid "__"; } \
|
88 |
+
static auto execute(const R &r, const L &l) -> decltype(expr) { return (expr); } \
|
89 |
+
static B execute_cast(const R &r, const L &l) { return B(expr); } \
|
90 |
+
}; \
|
91 |
+
inline op_<op_##id, op_l, self_t, self_t> op(const self_t &, const self_t &) { \
|
92 |
+
return op_<op_##id, op_l, self_t, self_t>(); \
|
93 |
+
} \
|
94 |
+
template <typename T> op_<op_##id, op_l, self_t, T> op(const self_t &, const T &) { \
|
95 |
+
return op_<op_##id, op_l, self_t, T>(); \
|
96 |
+
} \
|
97 |
+
template <typename T> op_<op_##id, op_r, T, self_t> op(const T &, const self_t &) { \
|
98 |
+
return op_<op_##id, op_r, T, self_t>(); \
|
99 |
+
}
|
100 |
+
|
101 |
+
#define PYBIND11_INPLACE_OPERATOR(id, op, expr) \
|
102 |
+
template <typename B, typename L, typename R> struct op_impl<op_##id, op_l, B, L, R> { \
|
103 |
+
static char const* name() { return "__" #id "__"; } \
|
104 |
+
static auto execute(L &l, const R &r) -> decltype(expr) { return expr; } \
|
105 |
+
static B execute_cast(L &l, const R &r) { return B(expr); } \
|
106 |
+
}; \
|
107 |
+
template <typename T> op_<op_##id, op_l, self_t, T> op(const self_t &, const T &) { \
|
108 |
+
return op_<op_##id, op_l, self_t, T>(); \
|
109 |
+
}
|
110 |
+
|
111 |
+
#define PYBIND11_UNARY_OPERATOR(id, op, expr) \
|
112 |
+
template <typename B, typename L> struct op_impl<op_##id, op_u, B, L, undefined_t> { \
|
113 |
+
static char const* name() { return "__" #id "__"; } \
|
114 |
+
static auto execute(const L &l) -> decltype(expr) { return expr; } \
|
115 |
+
static B execute_cast(const L &l) { return B(expr); } \
|
116 |
+
}; \
|
117 |
+
inline op_<op_##id, op_u, self_t, undefined_t> op(const self_t &) { \
|
118 |
+
return op_<op_##id, op_u, self_t, undefined_t>(); \
|
119 |
+
}
|
120 |
+
|
121 |
+
PYBIND11_BINARY_OPERATOR(sub, rsub, operator-, l - r)
|
122 |
+
PYBIND11_BINARY_OPERATOR(add, radd, operator+, l + r)
|
123 |
+
PYBIND11_BINARY_OPERATOR(mul, rmul, operator*, l * r)
|
124 |
+
PYBIND11_BINARY_OPERATOR(truediv, rtruediv, operator/, l / r)
|
125 |
+
PYBIND11_BINARY_OPERATOR(mod, rmod, operator%, l % r)
|
126 |
+
PYBIND11_BINARY_OPERATOR(lshift, rlshift, operator<<, l << r)
|
127 |
+
PYBIND11_BINARY_OPERATOR(rshift, rrshift, operator>>, l >> r)
|
128 |
+
PYBIND11_BINARY_OPERATOR(and, rand, operator&, l & r)
|
129 |
+
PYBIND11_BINARY_OPERATOR(xor, rxor, operator^, l ^ r)
|
130 |
+
PYBIND11_BINARY_OPERATOR(eq, eq, operator==, l == r)
|
131 |
+
PYBIND11_BINARY_OPERATOR(ne, ne, operator!=, l != r)
|
132 |
+
PYBIND11_BINARY_OPERATOR(or, ror, operator|, l | r)
|
133 |
+
PYBIND11_BINARY_OPERATOR(gt, lt, operator>, l > r)
|
134 |
+
PYBIND11_BINARY_OPERATOR(ge, le, operator>=, l >= r)
|
135 |
+
PYBIND11_BINARY_OPERATOR(lt, gt, operator<, l < r)
|
136 |
+
PYBIND11_BINARY_OPERATOR(le, ge, operator<=, l <= r)
|
137 |
+
//PYBIND11_BINARY_OPERATOR(pow, rpow, pow, std::pow(l, r))
|
138 |
+
PYBIND11_INPLACE_OPERATOR(iadd, operator+=, l += r)
|
139 |
+
PYBIND11_INPLACE_OPERATOR(isub, operator-=, l -= r)
|
140 |
+
PYBIND11_INPLACE_OPERATOR(imul, operator*=, l *= r)
|
141 |
+
PYBIND11_INPLACE_OPERATOR(itruediv, operator/=, l /= r)
|
142 |
+
PYBIND11_INPLACE_OPERATOR(imod, operator%=, l %= r)
|
143 |
+
PYBIND11_INPLACE_OPERATOR(ilshift, operator<<=, l <<= r)
|
144 |
+
PYBIND11_INPLACE_OPERATOR(irshift, operator>>=, l >>= r)
|
145 |
+
PYBIND11_INPLACE_OPERATOR(iand, operator&=, l &= r)
|
146 |
+
PYBIND11_INPLACE_OPERATOR(ixor, operator^=, l ^= r)
|
147 |
+
PYBIND11_INPLACE_OPERATOR(ior, operator|=, l |= r)
|
148 |
+
PYBIND11_UNARY_OPERATOR(neg, operator-, -l)
|
149 |
+
PYBIND11_UNARY_OPERATOR(pos, operator+, +l)
|
150 |
+
// WARNING: This usage of `abs` should only be done for existing STL overloads.
|
151 |
+
// Adding overloads directly in to the `std::` namespace is advised against:
|
152 |
+
// https://en.cppreference.com/w/cpp/language/extending_std
|
153 |
+
PYBIND11_UNARY_OPERATOR(abs, abs, std::abs(l))
|
154 |
+
PYBIND11_UNARY_OPERATOR(hash, hash, std::hash<L>()(l))
|
155 |
+
PYBIND11_UNARY_OPERATOR(invert, operator~, (~l))
|
156 |
+
PYBIND11_UNARY_OPERATOR(bool, operator!, !!l)
|
157 |
+
PYBIND11_UNARY_OPERATOR(int, int_, (int) l)
|
158 |
+
PYBIND11_UNARY_OPERATOR(float, float_, (double) l)
|
159 |
+
|
160 |
+
#undef PYBIND11_BINARY_OPERATOR
|
161 |
+
#undef PYBIND11_INPLACE_OPERATOR
|
162 |
+
#undef PYBIND11_UNARY_OPERATOR
|
163 |
+
PYBIND11_NAMESPACE_END(detail)
|
164 |
+
|
165 |
+
using detail::self;
|
166 |
+
// Add named operators so that they are accessible via `py::`.
|
167 |
+
using detail::hash;
|
168 |
+
|
169 |
+
PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)
|
170 |
+
|
171 |
+
#if defined(_MSC_VER)
|
172 |
+
# pragma warning(pop)
|
173 |
+
#endif
|
third-party/DPVO/Pangolin/components/pango_python/pybind11/include/pybind11/options.h
ADDED
@@ -0,0 +1,65 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/*
|
2 |
+
pybind11/options.h: global settings that are configurable at runtime.
|
3 |
+
|
4 |
+
Copyright (c) 2016 Wenzel Jakob <[email protected]>
|
5 |
+
|
6 |
+
All rights reserved. Use of this source code is governed by a
|
7 |
+
BSD-style license that can be found in the LICENSE file.
|
8 |
+
*/
|
9 |
+
|
10 |
+
#pragma once
|
11 |
+
|
12 |
+
#include "detail/common.h"
|
13 |
+
|
14 |
+
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
|
15 |
+
|
16 |
+
class options {
|
17 |
+
public:
|
18 |
+
|
19 |
+
// Default RAII constructor, which leaves settings as they currently are.
|
20 |
+
options() : previous_state(global_state()) {}
|
21 |
+
|
22 |
+
// Class is non-copyable.
|
23 |
+
options(const options&) = delete;
|
24 |
+
options& operator=(const options&) = delete;
|
25 |
+
|
26 |
+
// Destructor, which restores settings that were in effect before.
|
27 |
+
~options() {
|
28 |
+
global_state() = previous_state;
|
29 |
+
}
|
30 |
+
|
31 |
+
// Setter methods (affect the global state):
|
32 |
+
|
33 |
+
options& disable_user_defined_docstrings() & { global_state().show_user_defined_docstrings = false; return *this; }
|
34 |
+
|
35 |
+
options& enable_user_defined_docstrings() & { global_state().show_user_defined_docstrings = true; return *this; }
|
36 |
+
|
37 |
+
options& disable_function_signatures() & { global_state().show_function_signatures = false; return *this; }
|
38 |
+
|
39 |
+
options& enable_function_signatures() & { global_state().show_function_signatures = true; return *this; }
|
40 |
+
|
41 |
+
// Getter methods (return the global state):
|
42 |
+
|
43 |
+
static bool show_user_defined_docstrings() { return global_state().show_user_defined_docstrings; }
|
44 |
+
|
45 |
+
static bool show_function_signatures() { return global_state().show_function_signatures; }
|
46 |
+
|
47 |
+
// This type is not meant to be allocated on the heap.
|
48 |
+
void* operator new(size_t) = delete;
|
49 |
+
|
50 |
+
private:
|
51 |
+
|
52 |
+
struct state {
|
53 |
+
bool show_user_defined_docstrings = true; //< Include user-supplied texts in docstrings.
|
54 |
+
bool show_function_signatures = true; //< Include auto-generated function signatures in docstrings.
|
55 |
+
};
|
56 |
+
|
57 |
+
static state &global_state() {
|
58 |
+
static state instance;
|
59 |
+
return instance;
|
60 |
+
}
|
61 |
+
|
62 |
+
state previous_state;
|
63 |
+
};
|
64 |
+
|
65 |
+
PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)
|
third-party/DPVO/Pangolin/components/pango_python/pybind11/include/pybind11/pybind11.h
ADDED
The diff for this file is too large to render.
See raw diff
|
|
third-party/DPVO/Pangolin/components/pango_python/pybind11/include/pybind11/pytypes.h
ADDED
@@ -0,0 +1,1765 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/*
|
2 |
+
pybind11/pytypes.h: Convenience wrapper classes for basic Python types
|
3 |
+
|
4 |
+
Copyright (c) 2016 Wenzel Jakob <[email protected]>
|
5 |
+
|
6 |
+
All rights reserved. Use of this source code is governed by a
|
7 |
+
BSD-style license that can be found in the LICENSE file.
|
8 |
+
*/
|
9 |
+
|
10 |
+
#pragma once
|
11 |
+
|
12 |
+
#include "detail/common.h"
|
13 |
+
#include "buffer_info.h"
|
14 |
+
#include <utility>
|
15 |
+
#include <type_traits>
|
16 |
+
|
17 |
+
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
|
18 |
+
|
19 |
+
/* A few forward declarations */
|
20 |
+
class handle; class object;
|
21 |
+
class str; class iterator;
|
22 |
+
class type;
|
23 |
+
struct arg; struct arg_v;
|
24 |
+
|
25 |
+
PYBIND11_NAMESPACE_BEGIN(detail)
|
26 |
+
class args_proxy;
|
27 |
+
inline bool isinstance_generic(handle obj, const std::type_info &tp);
|
28 |
+
|
29 |
+
// Accessor forward declarations
|
30 |
+
template <typename Policy> class accessor;
|
31 |
+
namespace accessor_policies {
|
32 |
+
struct obj_attr;
|
33 |
+
struct str_attr;
|
34 |
+
struct generic_item;
|
35 |
+
struct sequence_item;
|
36 |
+
struct list_item;
|
37 |
+
struct tuple_item;
|
38 |
+
} // namespace accessor_policies
|
39 |
+
using obj_attr_accessor = accessor<accessor_policies::obj_attr>;
|
40 |
+
using str_attr_accessor = accessor<accessor_policies::str_attr>;
|
41 |
+
using item_accessor = accessor<accessor_policies::generic_item>;
|
42 |
+
using sequence_accessor = accessor<accessor_policies::sequence_item>;
|
43 |
+
using list_accessor = accessor<accessor_policies::list_item>;
|
44 |
+
using tuple_accessor = accessor<accessor_policies::tuple_item>;
|
45 |
+
|
46 |
+
/// Tag and check to identify a class which implements the Python object API
|
47 |
+
class pyobject_tag { };
|
48 |
+
template <typename T> using is_pyobject = std::is_base_of<pyobject_tag, remove_reference_t<T>>;
|
49 |
+
|
50 |
+
/** \rst
|
51 |
+
A mixin class which adds common functions to `handle`, `object` and various accessors.
|
52 |
+
The only requirement for `Derived` is to implement ``PyObject *Derived::ptr() const``.
|
53 |
+
\endrst */
|
54 |
+
template <typename Derived>
|
55 |
+
class object_api : public pyobject_tag {
|
56 |
+
const Derived &derived() const { return static_cast<const Derived &>(*this); }
|
57 |
+
|
58 |
+
public:
|
59 |
+
/** \rst
|
60 |
+
Return an iterator equivalent to calling ``iter()`` in Python. The object
|
61 |
+
must be a collection which supports the iteration protocol.
|
62 |
+
\endrst */
|
63 |
+
iterator begin() const;
|
64 |
+
/// Return a sentinel which ends iteration.
|
65 |
+
iterator end() const;
|
66 |
+
|
67 |
+
/** \rst
|
68 |
+
Return an internal functor to invoke the object's sequence protocol. Casting
|
69 |
+
the returned ``detail::item_accessor`` instance to a `handle` or `object`
|
70 |
+
subclass causes a corresponding call to ``__getitem__``. Assigning a `handle`
|
71 |
+
or `object` subclass causes a call to ``__setitem__``.
|
72 |
+
\endrst */
|
73 |
+
item_accessor operator[](handle key) const;
|
74 |
+
/// See above (the only difference is that they key is provided as a string literal)
|
75 |
+
item_accessor operator[](const char *key) const;
|
76 |
+
|
77 |
+
/** \rst
|
78 |
+
Return an internal functor to access the object's attributes. Casting the
|
79 |
+
returned ``detail::obj_attr_accessor`` instance to a `handle` or `object`
|
80 |
+
subclass causes a corresponding call to ``getattr``. Assigning a `handle`
|
81 |
+
or `object` subclass causes a call to ``setattr``.
|
82 |
+
\endrst */
|
83 |
+
obj_attr_accessor attr(handle key) const;
|
84 |
+
/// See above (the only difference is that they key is provided as a string literal)
|
85 |
+
str_attr_accessor attr(const char *key) const;
|
86 |
+
|
87 |
+
/** \rst
|
88 |
+
Matches * unpacking in Python, e.g. to unpack arguments out of a ``tuple``
|
89 |
+
or ``list`` for a function call. Applying another * to the result yields
|
90 |
+
** unpacking, e.g. to unpack a dict as function keyword arguments.
|
91 |
+
See :ref:`calling_python_functions`.
|
92 |
+
\endrst */
|
93 |
+
args_proxy operator*() const;
|
94 |
+
|
95 |
+
/// Check if the given item is contained within this object, i.e. ``item in obj``.
|
96 |
+
template <typename T> bool contains(T &&item) const;
|
97 |
+
|
98 |
+
/** \rst
|
99 |
+
Assuming the Python object is a function or implements the ``__call__``
|
100 |
+
protocol, ``operator()`` invokes the underlying function, passing an
|
101 |
+
arbitrary set of parameters. The result is returned as a `object` and
|
102 |
+
may need to be converted back into a Python object using `handle::cast()`.
|
103 |
+
|
104 |
+
When some of the arguments cannot be converted to Python objects, the
|
105 |
+
function will throw a `cast_error` exception. When the Python function
|
106 |
+
call fails, a `error_already_set` exception is thrown.
|
107 |
+
\endrst */
|
108 |
+
template <return_value_policy policy = return_value_policy::automatic_reference, typename... Args>
|
109 |
+
object operator()(Args &&...args) const;
|
110 |
+
template <return_value_policy policy = return_value_policy::automatic_reference, typename... Args>
|
111 |
+
PYBIND11_DEPRECATED("call(...) was deprecated in favor of operator()(...)")
|
112 |
+
object call(Args&&... args) const;
|
113 |
+
|
114 |
+
/// Equivalent to ``obj is other`` in Python.
|
115 |
+
bool is(object_api const& other) const { return derived().ptr() == other.derived().ptr(); }
|
116 |
+
/// Equivalent to ``obj is None`` in Python.
|
117 |
+
bool is_none() const { return derived().ptr() == Py_None; }
|
118 |
+
/// Equivalent to obj == other in Python
|
119 |
+
bool equal(object_api const &other) const { return rich_compare(other, Py_EQ); }
|
120 |
+
bool not_equal(object_api const &other) const { return rich_compare(other, Py_NE); }
|
121 |
+
bool operator<(object_api const &other) const { return rich_compare(other, Py_LT); }
|
122 |
+
bool operator<=(object_api const &other) const { return rich_compare(other, Py_LE); }
|
123 |
+
bool operator>(object_api const &other) const { return rich_compare(other, Py_GT); }
|
124 |
+
bool operator>=(object_api const &other) const { return rich_compare(other, Py_GE); }
|
125 |
+
|
126 |
+
object operator-() const;
|
127 |
+
object operator~() const;
|
128 |
+
object operator+(object_api const &other) const;
|
129 |
+
object operator+=(object_api const &other) const;
|
130 |
+
object operator-(object_api const &other) const;
|
131 |
+
object operator-=(object_api const &other) const;
|
132 |
+
object operator*(object_api const &other) const;
|
133 |
+
object operator*=(object_api const &other) const;
|
134 |
+
object operator/(object_api const &other) const;
|
135 |
+
object operator/=(object_api const &other) const;
|
136 |
+
object operator|(object_api const &other) const;
|
137 |
+
object operator|=(object_api const &other) const;
|
138 |
+
object operator&(object_api const &other) const;
|
139 |
+
object operator&=(object_api const &other) const;
|
140 |
+
object operator^(object_api const &other) const;
|
141 |
+
object operator^=(object_api const &other) const;
|
142 |
+
object operator<<(object_api const &other) const;
|
143 |
+
object operator<<=(object_api const &other) const;
|
144 |
+
object operator>>(object_api const &other) const;
|
145 |
+
object operator>>=(object_api const &other) const;
|
146 |
+
|
147 |
+
PYBIND11_DEPRECATED("Use py::str(obj) instead")
|
148 |
+
pybind11::str str() const;
|
149 |
+
|
150 |
+
/// Get or set the object's docstring, i.e. ``obj.__doc__``.
|
151 |
+
str_attr_accessor doc() const;
|
152 |
+
|
153 |
+
/// Return the object's current reference count
|
154 |
+
int ref_count() const { return static_cast<int>(Py_REFCNT(derived().ptr())); }
|
155 |
+
|
156 |
+
// TODO PYBIND11_DEPRECATED("Call py::type::handle_of(h) or py::type::of(h) instead of h.get_type()")
|
157 |
+
handle get_type() const;
|
158 |
+
|
159 |
+
private:
|
160 |
+
bool rich_compare(object_api const &other, int value) const;
|
161 |
+
};
|
162 |
+
|
163 |
+
PYBIND11_NAMESPACE_END(detail)
|
164 |
+
|
165 |
+
/** \rst
|
166 |
+
Holds a reference to a Python object (no reference counting)
|
167 |
+
|
168 |
+
The `handle` class is a thin wrapper around an arbitrary Python object (i.e. a
|
169 |
+
``PyObject *`` in Python's C API). It does not perform any automatic reference
|
170 |
+
counting and merely provides a basic C++ interface to various Python API functions.
|
171 |
+
|
172 |
+
.. seealso::
|
173 |
+
The `object` class inherits from `handle` and adds automatic reference
|
174 |
+
counting features.
|
175 |
+
\endrst */
|
176 |
+
class handle : public detail::object_api<handle> {
|
177 |
+
public:
|
178 |
+
/// The default constructor creates a handle with a ``nullptr``-valued pointer
|
179 |
+
handle() = default;
|
180 |
+
/// Creates a ``handle`` from the given raw Python object pointer
|
181 |
+
handle(PyObject *ptr) : m_ptr(ptr) { } // Allow implicit conversion from PyObject*
|
182 |
+
|
183 |
+
/// Return the underlying ``PyObject *`` pointer
|
184 |
+
PyObject *ptr() const { return m_ptr; }
|
185 |
+
PyObject *&ptr() { return m_ptr; }
|
186 |
+
|
187 |
+
/** \rst
|
188 |
+
Manually increase the reference count of the Python object. Usually, it is
|
189 |
+
preferable to use the `object` class which derives from `handle` and calls
|
190 |
+
this function automatically. Returns a reference to itself.
|
191 |
+
\endrst */
|
192 |
+
const handle& inc_ref() const & { Py_XINCREF(m_ptr); return *this; }
|
193 |
+
|
194 |
+
/** \rst
|
195 |
+
Manually decrease the reference count of the Python object. Usually, it is
|
196 |
+
preferable to use the `object` class which derives from `handle` and calls
|
197 |
+
this function automatically. Returns a reference to itself.
|
198 |
+
\endrst */
|
199 |
+
const handle& dec_ref() const & { Py_XDECREF(m_ptr); return *this; }
|
200 |
+
|
201 |
+
/** \rst
|
202 |
+
Attempt to cast the Python object into the given C++ type. A `cast_error`
|
203 |
+
will be throw upon failure.
|
204 |
+
\endrst */
|
205 |
+
template <typename T> T cast() const;
|
206 |
+
/// Return ``true`` when the `handle` wraps a valid Python object
|
207 |
+
explicit operator bool() const { return m_ptr != nullptr; }
|
208 |
+
/** \rst
|
209 |
+
Deprecated: Check that the underlying pointers are the same.
|
210 |
+
Equivalent to ``obj1 is obj2`` in Python.
|
211 |
+
\endrst */
|
212 |
+
PYBIND11_DEPRECATED("Use obj1.is(obj2) instead")
|
213 |
+
bool operator==(const handle &h) const { return m_ptr == h.m_ptr; }
|
214 |
+
PYBIND11_DEPRECATED("Use !obj1.is(obj2) instead")
|
215 |
+
bool operator!=(const handle &h) const { return m_ptr != h.m_ptr; }
|
216 |
+
PYBIND11_DEPRECATED("Use handle::operator bool() instead")
|
217 |
+
bool check() const { return m_ptr != nullptr; }
|
218 |
+
protected:
|
219 |
+
PyObject *m_ptr = nullptr;
|
220 |
+
};
|
221 |
+
|
222 |
+
/** \rst
|
223 |
+
Holds a reference to a Python object (with reference counting)
|
224 |
+
|
225 |
+
Like `handle`, the `object` class is a thin wrapper around an arbitrary Python
|
226 |
+
object (i.e. a ``PyObject *`` in Python's C API). In contrast to `handle`, it
|
227 |
+
optionally increases the object's reference count upon construction, and it
|
228 |
+
*always* decreases the reference count when the `object` instance goes out of
|
229 |
+
scope and is destructed. When using `object` instances consistently, it is much
|
230 |
+
easier to get reference counting right at the first attempt.
|
231 |
+
\endrst */
|
232 |
+
class object : public handle {
|
233 |
+
public:
|
234 |
+
object() = default;
|
235 |
+
PYBIND11_DEPRECATED("Use reinterpret_borrow<object>() or reinterpret_steal<object>()")
|
236 |
+
object(handle h, bool is_borrowed) : handle(h) { if (is_borrowed) inc_ref(); }
|
237 |
+
/// Copy constructor; always increases the reference count
|
238 |
+
object(const object &o) : handle(o) { inc_ref(); }
|
239 |
+
/// Move constructor; steals the object from ``other`` and preserves its reference count
|
240 |
+
object(object &&other) noexcept { m_ptr = other.m_ptr; other.m_ptr = nullptr; }
|
241 |
+
/// Destructor; automatically calls `handle::dec_ref()`
|
242 |
+
~object() { dec_ref(); }
|
243 |
+
|
244 |
+
/** \rst
|
245 |
+
Resets the internal pointer to ``nullptr`` without decreasing the
|
246 |
+
object's reference count. The function returns a raw handle to the original
|
247 |
+
Python object.
|
248 |
+
\endrst */
|
249 |
+
handle release() {
|
250 |
+
PyObject *tmp = m_ptr;
|
251 |
+
m_ptr = nullptr;
|
252 |
+
return handle(tmp);
|
253 |
+
}
|
254 |
+
|
255 |
+
object& operator=(const object &other) {
|
256 |
+
other.inc_ref();
|
257 |
+
dec_ref();
|
258 |
+
m_ptr = other.m_ptr;
|
259 |
+
return *this;
|
260 |
+
}
|
261 |
+
|
262 |
+
object& operator=(object &&other) noexcept {
|
263 |
+
if (this != &other) {
|
264 |
+
handle temp(m_ptr);
|
265 |
+
m_ptr = other.m_ptr;
|
266 |
+
other.m_ptr = nullptr;
|
267 |
+
temp.dec_ref();
|
268 |
+
}
|
269 |
+
return *this;
|
270 |
+
}
|
271 |
+
|
272 |
+
// Calling cast() on an object lvalue just copies (via handle::cast)
|
273 |
+
template <typename T> T cast() const &;
|
274 |
+
// Calling on an object rvalue does a move, if needed and/or possible
|
275 |
+
template <typename T> T cast() &&;
|
276 |
+
|
277 |
+
protected:
|
278 |
+
// Tags for choosing constructors from raw PyObject *
|
279 |
+
struct borrowed_t { };
|
280 |
+
struct stolen_t { };
|
281 |
+
|
282 |
+
#ifndef DOXYGEN_SHOULD_SKIP_THIS // Issue in breathe 4.26.1
|
283 |
+
template <typename T> friend T reinterpret_borrow(handle);
|
284 |
+
template <typename T> friend T reinterpret_steal(handle);
|
285 |
+
#endif
|
286 |
+
|
287 |
+
public:
|
288 |
+
// Only accessible from derived classes and the reinterpret_* functions
|
289 |
+
object(handle h, borrowed_t) : handle(h) { inc_ref(); }
|
290 |
+
object(handle h, stolen_t) : handle(h) { }
|
291 |
+
};
|
292 |
+
|
293 |
+
/** \rst
|
294 |
+
Declare that a `handle` or ``PyObject *`` is a certain type and borrow the reference.
|
295 |
+
The target type ``T`` must be `object` or one of its derived classes. The function
|
296 |
+
doesn't do any conversions or checks. It's up to the user to make sure that the
|
297 |
+
target type is correct.
|
298 |
+
|
299 |
+
.. code-block:: cpp
|
300 |
+
|
301 |
+
PyObject *p = PyList_GetItem(obj, index);
|
302 |
+
py::object o = reinterpret_borrow<py::object>(p);
|
303 |
+
// or
|
304 |
+
py::tuple t = reinterpret_borrow<py::tuple>(p); // <-- `p` must be already be a `tuple`
|
305 |
+
\endrst */
|
306 |
+
template <typename T> T reinterpret_borrow(handle h) { return {h, object::borrowed_t{}}; }
|
307 |
+
|
308 |
+
/** \rst
|
309 |
+
Like `reinterpret_borrow`, but steals the reference.
|
310 |
+
|
311 |
+
.. code-block:: cpp
|
312 |
+
|
313 |
+
PyObject *p = PyObject_Str(obj);
|
314 |
+
py::str s = reinterpret_steal<py::str>(p); // <-- `p` must be already be a `str`
|
315 |
+
\endrst */
|
316 |
+
template <typename T> T reinterpret_steal(handle h) { return {h, object::stolen_t{}}; }
|
317 |
+
|
318 |
+
PYBIND11_NAMESPACE_BEGIN(detail)
|
319 |
+
inline std::string error_string();
|
320 |
+
PYBIND11_NAMESPACE_END(detail)
|
321 |
+
|
322 |
+
#if defined(_MSC_VER)
|
323 |
+
# pragma warning(push)
|
324 |
+
# pragma warning(disable: 4275 4251) // warning C4275: An exported class was derived from a class that wasn't exported. Can be ignored when derived from a STL class.
|
325 |
+
#endif
|
326 |
+
/// Fetch and hold an error which was already set in Python. An instance of this is typically
|
327 |
+
/// thrown to propagate python-side errors back through C++ which can either be caught manually or
|
328 |
+
/// else falls back to the function dispatcher (which then raises the captured error back to
|
329 |
+
/// python).
|
330 |
+
class PYBIND11_EXPORT_EXCEPTION error_already_set : public std::runtime_error {
|
331 |
+
public:
|
332 |
+
/// Constructs a new exception from the current Python error indicator, if any. The current
|
333 |
+
/// Python error indicator will be cleared.
|
334 |
+
error_already_set() : std::runtime_error(detail::error_string()) {
|
335 |
+
PyErr_Fetch(&m_type.ptr(), &m_value.ptr(), &m_trace.ptr());
|
336 |
+
}
|
337 |
+
|
338 |
+
error_already_set(const error_already_set &) = default;
|
339 |
+
error_already_set(error_already_set &&) = default;
|
340 |
+
|
341 |
+
inline ~error_already_set() override;
|
342 |
+
|
343 |
+
/// Give the currently-held error back to Python, if any. If there is currently a Python error
|
344 |
+
/// already set it is cleared first. After this call, the current object no longer stores the
|
345 |
+
/// error variables (but the `.what()` string is still available).
|
346 |
+
void restore() { PyErr_Restore(m_type.release().ptr(), m_value.release().ptr(), m_trace.release().ptr()); }
|
347 |
+
|
348 |
+
/// If it is impossible to raise the currently-held error, such as in a destructor, we can write
|
349 |
+
/// it out using Python's unraisable hook (`sys.unraisablehook`). The error context should be
|
350 |
+
/// some object whose `repr()` helps identify the location of the error. Python already knows the
|
351 |
+
/// type and value of the error, so there is no need to repeat that. After this call, the current
|
352 |
+
/// object no longer stores the error variables, and neither does Python.
|
353 |
+
void discard_as_unraisable(object err_context) {
|
354 |
+
restore();
|
355 |
+
PyErr_WriteUnraisable(err_context.ptr());
|
356 |
+
}
|
357 |
+
/// An alternate version of `discard_as_unraisable()`, where a string provides information on the
|
358 |
+
/// location of the error. For example, `__func__` could be helpful.
|
359 |
+
void discard_as_unraisable(const char *err_context) {
|
360 |
+
discard_as_unraisable(reinterpret_steal<object>(PYBIND11_FROM_STRING(err_context)));
|
361 |
+
}
|
362 |
+
|
363 |
+
// Does nothing; provided for backwards compatibility.
|
364 |
+
PYBIND11_DEPRECATED("Use of error_already_set.clear() is deprecated")
|
365 |
+
void clear() {}
|
366 |
+
|
367 |
+
/// Check if the currently trapped error type matches the given Python exception class (or a
|
368 |
+
/// subclass thereof). May also be passed a tuple to search for any exception class matches in
|
369 |
+
/// the given tuple.
|
370 |
+
bool matches(handle exc) const {
|
371 |
+
return (PyErr_GivenExceptionMatches(m_type.ptr(), exc.ptr()) != 0);
|
372 |
+
}
|
373 |
+
|
374 |
+
const object& type() const { return m_type; }
|
375 |
+
const object& value() const { return m_value; }
|
376 |
+
const object& trace() const { return m_trace; }
|
377 |
+
|
378 |
+
private:
|
379 |
+
object m_type, m_value, m_trace;
|
380 |
+
};
|
381 |
+
#if defined(_MSC_VER)
|
382 |
+
# pragma warning(pop)
|
383 |
+
#endif
|
384 |
+
|
385 |
+
/** \defgroup python_builtins _
|
386 |
+
Unless stated otherwise, the following C++ functions behave the same
|
387 |
+
as their Python counterparts.
|
388 |
+
*/
|
389 |
+
|
390 |
+
/** \ingroup python_builtins
|
391 |
+
\rst
|
392 |
+
Return true if ``obj`` is an instance of ``T``. Type ``T`` must be a subclass of
|
393 |
+
`object` or a class which was exposed to Python as ``py::class_<T>``.
|
394 |
+
\endrst */
|
395 |
+
template <typename T, detail::enable_if_t<std::is_base_of<object, T>::value, int> = 0>
|
396 |
+
bool isinstance(handle obj) { return T::check_(obj); }
|
397 |
+
|
398 |
+
template <typename T, detail::enable_if_t<!std::is_base_of<object, T>::value, int> = 0>
|
399 |
+
bool isinstance(handle obj) { return detail::isinstance_generic(obj, typeid(T)); }
|
400 |
+
|
401 |
+
template <> inline bool isinstance<handle>(handle) = delete;
|
402 |
+
template <> inline bool isinstance<object>(handle obj) { return obj.ptr() != nullptr; }
|
403 |
+
|
404 |
+
/// \ingroup python_builtins
|
405 |
+
/// Return true if ``obj`` is an instance of the ``type``.
|
406 |
+
inline bool isinstance(handle obj, handle type) {
|
407 |
+
const auto result = PyObject_IsInstance(obj.ptr(), type.ptr());
|
408 |
+
if (result == -1)
|
409 |
+
throw error_already_set();
|
410 |
+
return result != 0;
|
411 |
+
}
|
412 |
+
|
413 |
+
/// \addtogroup python_builtins
|
414 |
+
/// @{
|
415 |
+
inline bool hasattr(handle obj, handle name) {
|
416 |
+
return PyObject_HasAttr(obj.ptr(), name.ptr()) == 1;
|
417 |
+
}
|
418 |
+
|
419 |
+
inline bool hasattr(handle obj, const char *name) {
|
420 |
+
return PyObject_HasAttrString(obj.ptr(), name) == 1;
|
421 |
+
}
|
422 |
+
|
423 |
+
inline void delattr(handle obj, handle name) {
|
424 |
+
if (PyObject_DelAttr(obj.ptr(), name.ptr()) != 0) { throw error_already_set(); }
|
425 |
+
}
|
426 |
+
|
427 |
+
inline void delattr(handle obj, const char *name) {
|
428 |
+
if (PyObject_DelAttrString(obj.ptr(), name) != 0) { throw error_already_set(); }
|
429 |
+
}
|
430 |
+
|
431 |
+
inline object getattr(handle obj, handle name) {
|
432 |
+
PyObject *result = PyObject_GetAttr(obj.ptr(), name.ptr());
|
433 |
+
if (!result) { throw error_already_set(); }
|
434 |
+
return reinterpret_steal<object>(result);
|
435 |
+
}
|
436 |
+
|
437 |
+
inline object getattr(handle obj, const char *name) {
|
438 |
+
PyObject *result = PyObject_GetAttrString(obj.ptr(), name);
|
439 |
+
if (!result) { throw error_already_set(); }
|
440 |
+
return reinterpret_steal<object>(result);
|
441 |
+
}
|
442 |
+
|
443 |
+
inline object getattr(handle obj, handle name, handle default_) {
|
444 |
+
if (PyObject *result = PyObject_GetAttr(obj.ptr(), name.ptr())) {
|
445 |
+
return reinterpret_steal<object>(result);
|
446 |
+
}
|
447 |
+
PyErr_Clear();
|
448 |
+
return reinterpret_borrow<object>(default_);
|
449 |
+
}
|
450 |
+
|
451 |
+
inline object getattr(handle obj, const char *name, handle default_) {
|
452 |
+
if (PyObject *result = PyObject_GetAttrString(obj.ptr(), name)) {
|
453 |
+
return reinterpret_steal<object>(result);
|
454 |
+
}
|
455 |
+
PyErr_Clear();
|
456 |
+
return reinterpret_borrow<object>(default_);
|
457 |
+
}
|
458 |
+
|
459 |
+
inline void setattr(handle obj, handle name, handle value) {
|
460 |
+
if (PyObject_SetAttr(obj.ptr(), name.ptr(), value.ptr()) != 0) { throw error_already_set(); }
|
461 |
+
}
|
462 |
+
|
463 |
+
inline void setattr(handle obj, const char *name, handle value) {
|
464 |
+
if (PyObject_SetAttrString(obj.ptr(), name, value.ptr()) != 0) { throw error_already_set(); }
|
465 |
+
}
|
466 |
+
|
467 |
+
inline ssize_t hash(handle obj) {
|
468 |
+
auto h = PyObject_Hash(obj.ptr());
|
469 |
+
if (h == -1) { throw error_already_set(); }
|
470 |
+
return h;
|
471 |
+
}
|
472 |
+
|
473 |
+
/// @} python_builtins
|
474 |
+
|
475 |
+
PYBIND11_NAMESPACE_BEGIN(detail)
|
476 |
+
inline handle get_function(handle value) {
|
477 |
+
if (value) {
|
478 |
+
#if PY_MAJOR_VERSION >= 3
|
479 |
+
if (PyInstanceMethod_Check(value.ptr()))
|
480 |
+
value = PyInstanceMethod_GET_FUNCTION(value.ptr());
|
481 |
+
else
|
482 |
+
#endif
|
483 |
+
if (PyMethod_Check(value.ptr()))
|
484 |
+
value = PyMethod_GET_FUNCTION(value.ptr());
|
485 |
+
}
|
486 |
+
return value;
|
487 |
+
}
|
488 |
+
|
489 |
+
// Reimplementation of python's dict helper functions to ensure that exceptions
|
490 |
+
// aren't swallowed (see #2862)
|
491 |
+
|
492 |
+
// copied from cpython _PyDict_GetItemStringWithError
|
493 |
+
inline PyObject * dict_getitemstring(PyObject *v, const char *key)
|
494 |
+
{
|
495 |
+
#if PY_MAJOR_VERSION >= 3
|
496 |
+
PyObject *kv = nullptr, *rv = nullptr;
|
497 |
+
kv = PyUnicode_FromString(key);
|
498 |
+
if (kv == NULL) {
|
499 |
+
throw error_already_set();
|
500 |
+
}
|
501 |
+
|
502 |
+
rv = PyDict_GetItemWithError(v, kv);
|
503 |
+
Py_DECREF(kv);
|
504 |
+
if (rv == NULL && PyErr_Occurred()) {
|
505 |
+
throw error_already_set();
|
506 |
+
}
|
507 |
+
return rv;
|
508 |
+
#else
|
509 |
+
return PyDict_GetItemString(v, key);
|
510 |
+
#endif
|
511 |
+
}
|
512 |
+
|
513 |
+
inline PyObject * dict_getitem(PyObject *v, PyObject *key)
|
514 |
+
{
|
515 |
+
#if PY_MAJOR_VERSION >= 3
|
516 |
+
PyObject *rv = PyDict_GetItemWithError(v, key);
|
517 |
+
if (rv == NULL && PyErr_Occurred()) {
|
518 |
+
throw error_already_set();
|
519 |
+
}
|
520 |
+
return rv;
|
521 |
+
#else
|
522 |
+
return PyDict_GetItem(v, key);
|
523 |
+
#endif
|
524 |
+
}
|
525 |
+
|
526 |
+
// Helper aliases/functions to support implicit casting of values given to python accessors/methods.
|
527 |
+
// When given a pyobject, this simply returns the pyobject as-is; for other C++ type, the value goes
|
528 |
+
// through pybind11::cast(obj) to convert it to an `object`.
|
529 |
+
template <typename T, enable_if_t<is_pyobject<T>::value, int> = 0>
|
530 |
+
auto object_or_cast(T &&o) -> decltype(std::forward<T>(o)) { return std::forward<T>(o); }
|
531 |
+
// The following casting version is implemented in cast.h:
|
532 |
+
template <typename T, enable_if_t<!is_pyobject<T>::value, int> = 0>
|
533 |
+
object object_or_cast(T &&o);
|
534 |
+
// Match a PyObject*, which we want to convert directly to handle via its converting constructor
|
535 |
+
inline handle object_or_cast(PyObject *ptr) { return ptr; }
|
536 |
+
|
537 |
+
#if defined(_MSC_VER) && _MSC_VER < 1920
|
538 |
+
# pragma warning(push)
|
539 |
+
# pragma warning(disable: 4522) // warning C4522: multiple assignment operators specified
|
540 |
+
#endif
|
541 |
+
template <typename Policy>
|
542 |
+
class accessor : public object_api<accessor<Policy>> {
|
543 |
+
using key_type = typename Policy::key_type;
|
544 |
+
|
545 |
+
public:
|
546 |
+
accessor(handle obj, key_type key) : obj(obj), key(std::move(key)) { }
|
547 |
+
accessor(const accessor &) = default;
|
548 |
+
accessor(accessor &&) noexcept = default;
|
549 |
+
|
550 |
+
// accessor overload required to override default assignment operator (templates are not allowed
|
551 |
+
// to replace default compiler-generated assignments).
|
552 |
+
void operator=(const accessor &a) && { std::move(*this).operator=(handle(a)); }
|
553 |
+
void operator=(const accessor &a) & { operator=(handle(a)); }
|
554 |
+
|
555 |
+
template <typename T> void operator=(T &&value) && {
|
556 |
+
Policy::set(obj, key, object_or_cast(std::forward<T>(value)));
|
557 |
+
}
|
558 |
+
template <typename T> void operator=(T &&value) & {
|
559 |
+
get_cache() = reinterpret_borrow<object>(object_or_cast(std::forward<T>(value)));
|
560 |
+
}
|
561 |
+
|
562 |
+
template <typename T = Policy>
|
563 |
+
PYBIND11_DEPRECATED("Use of obj.attr(...) as bool is deprecated in favor of pybind11::hasattr(obj, ...)")
|
564 |
+
explicit operator enable_if_t<std::is_same<T, accessor_policies::str_attr>::value ||
|
565 |
+
std::is_same<T, accessor_policies::obj_attr>::value, bool>() const {
|
566 |
+
return hasattr(obj, key);
|
567 |
+
}
|
568 |
+
template <typename T = Policy>
|
569 |
+
PYBIND11_DEPRECATED("Use of obj[key] as bool is deprecated in favor of obj.contains(key)")
|
570 |
+
explicit operator enable_if_t<std::is_same<T, accessor_policies::generic_item>::value, bool>() const {
|
571 |
+
return obj.contains(key);
|
572 |
+
}
|
573 |
+
|
574 |
+
operator object() const { return get_cache(); }
|
575 |
+
PyObject *ptr() const { return get_cache().ptr(); }
|
576 |
+
template <typename T> T cast() const { return get_cache().template cast<T>(); }
|
577 |
+
|
578 |
+
private:
|
579 |
+
object &get_cache() const {
|
580 |
+
if (!cache) { cache = Policy::get(obj, key); }
|
581 |
+
return cache;
|
582 |
+
}
|
583 |
+
|
584 |
+
private:
|
585 |
+
handle obj;
|
586 |
+
key_type key;
|
587 |
+
mutable object cache;
|
588 |
+
};
|
589 |
+
#if defined(_MSC_VER) && _MSC_VER < 1920
|
590 |
+
# pragma warning(pop)
|
591 |
+
#endif
|
592 |
+
|
593 |
+
PYBIND11_NAMESPACE_BEGIN(accessor_policies)
|
594 |
+
struct obj_attr {
|
595 |
+
using key_type = object;
|
596 |
+
static object get(handle obj, handle key) { return getattr(obj, key); }
|
597 |
+
static void set(handle obj, handle key, handle val) { setattr(obj, key, val); }
|
598 |
+
};
|
599 |
+
|
600 |
+
struct str_attr {
|
601 |
+
using key_type = const char *;
|
602 |
+
static object get(handle obj, const char *key) { return getattr(obj, key); }
|
603 |
+
static void set(handle obj, const char *key, handle val) { setattr(obj, key, val); }
|
604 |
+
};
|
605 |
+
|
606 |
+
struct generic_item {
|
607 |
+
using key_type = object;
|
608 |
+
|
609 |
+
static object get(handle obj, handle key) {
|
610 |
+
PyObject *result = PyObject_GetItem(obj.ptr(), key.ptr());
|
611 |
+
if (!result) { throw error_already_set(); }
|
612 |
+
return reinterpret_steal<object>(result);
|
613 |
+
}
|
614 |
+
|
615 |
+
static void set(handle obj, handle key, handle val) {
|
616 |
+
if (PyObject_SetItem(obj.ptr(), key.ptr(), val.ptr()) != 0) { throw error_already_set(); }
|
617 |
+
}
|
618 |
+
};
|
619 |
+
|
620 |
+
struct sequence_item {
|
621 |
+
using key_type = size_t;
|
622 |
+
|
623 |
+
static object get(handle obj, size_t index) {
|
624 |
+
PyObject *result = PySequence_GetItem(obj.ptr(), static_cast<ssize_t>(index));
|
625 |
+
if (!result) { throw error_already_set(); }
|
626 |
+
return reinterpret_steal<object>(result);
|
627 |
+
}
|
628 |
+
|
629 |
+
static void set(handle obj, size_t index, handle val) {
|
630 |
+
// PySequence_SetItem does not steal a reference to 'val'
|
631 |
+
if (PySequence_SetItem(obj.ptr(), static_cast<ssize_t>(index), val.ptr()) != 0) {
|
632 |
+
throw error_already_set();
|
633 |
+
}
|
634 |
+
}
|
635 |
+
};
|
636 |
+
|
637 |
+
struct list_item {
|
638 |
+
using key_type = size_t;
|
639 |
+
|
640 |
+
static object get(handle obj, size_t index) {
|
641 |
+
PyObject *result = PyList_GetItem(obj.ptr(), static_cast<ssize_t>(index));
|
642 |
+
if (!result) { throw error_already_set(); }
|
643 |
+
return reinterpret_borrow<object>(result);
|
644 |
+
}
|
645 |
+
|
646 |
+
static void set(handle obj, size_t index, handle val) {
|
647 |
+
// PyList_SetItem steals a reference to 'val'
|
648 |
+
if (PyList_SetItem(obj.ptr(), static_cast<ssize_t>(index), val.inc_ref().ptr()) != 0) {
|
649 |
+
throw error_already_set();
|
650 |
+
}
|
651 |
+
}
|
652 |
+
};
|
653 |
+
|
654 |
+
struct tuple_item {
|
655 |
+
using key_type = size_t;
|
656 |
+
|
657 |
+
static object get(handle obj, size_t index) {
|
658 |
+
PyObject *result = PyTuple_GetItem(obj.ptr(), static_cast<ssize_t>(index));
|
659 |
+
if (!result) { throw error_already_set(); }
|
660 |
+
return reinterpret_borrow<object>(result);
|
661 |
+
}
|
662 |
+
|
663 |
+
static void set(handle obj, size_t index, handle val) {
|
664 |
+
// PyTuple_SetItem steals a reference to 'val'
|
665 |
+
if (PyTuple_SetItem(obj.ptr(), static_cast<ssize_t>(index), val.inc_ref().ptr()) != 0) {
|
666 |
+
throw error_already_set();
|
667 |
+
}
|
668 |
+
}
|
669 |
+
};
|
670 |
+
PYBIND11_NAMESPACE_END(accessor_policies)
|
671 |
+
|
672 |
+
/// STL iterator template used for tuple, list, sequence and dict
|
673 |
+
template <typename Policy>
|
674 |
+
class generic_iterator : public Policy {
|
675 |
+
using It = generic_iterator;
|
676 |
+
|
677 |
+
public:
|
678 |
+
using difference_type = ssize_t;
|
679 |
+
using iterator_category = typename Policy::iterator_category;
|
680 |
+
using value_type = typename Policy::value_type;
|
681 |
+
using reference = typename Policy::reference;
|
682 |
+
using pointer = typename Policy::pointer;
|
683 |
+
|
684 |
+
generic_iterator() = default;
|
685 |
+
generic_iterator(handle seq, ssize_t index) : Policy(seq, index) { }
|
686 |
+
|
687 |
+
reference operator*() const { return Policy::dereference(); }
|
688 |
+
reference operator[](difference_type n) const { return *(*this + n); }
|
689 |
+
pointer operator->() const { return **this; }
|
690 |
+
|
691 |
+
It &operator++() { Policy::increment(); return *this; }
|
692 |
+
It operator++(int) { auto copy = *this; Policy::increment(); return copy; }
|
693 |
+
It &operator--() { Policy::decrement(); return *this; }
|
694 |
+
It operator--(int) { auto copy = *this; Policy::decrement(); return copy; }
|
695 |
+
It &operator+=(difference_type n) { Policy::advance(n); return *this; }
|
696 |
+
It &operator-=(difference_type n) { Policy::advance(-n); return *this; }
|
697 |
+
|
698 |
+
friend It operator+(const It &a, difference_type n) { auto copy = a; return copy += n; }
|
699 |
+
friend It operator+(difference_type n, const It &b) { return b + n; }
|
700 |
+
friend It operator-(const It &a, difference_type n) { auto copy = a; return copy -= n; }
|
701 |
+
friend difference_type operator-(const It &a, const It &b) { return a.distance_to(b); }
|
702 |
+
|
703 |
+
friend bool operator==(const It &a, const It &b) { return a.equal(b); }
|
704 |
+
friend bool operator!=(const It &a, const It &b) { return !(a == b); }
|
705 |
+
friend bool operator< (const It &a, const It &b) { return b - a > 0; }
|
706 |
+
friend bool operator> (const It &a, const It &b) { return b < a; }
|
707 |
+
friend bool operator>=(const It &a, const It &b) { return !(a < b); }
|
708 |
+
friend bool operator<=(const It &a, const It &b) { return !(a > b); }
|
709 |
+
};
|
710 |
+
|
711 |
+
PYBIND11_NAMESPACE_BEGIN(iterator_policies)
|
712 |
+
/// Quick proxy class needed to implement ``operator->`` for iterators which can't return pointers
|
713 |
+
template <typename T>
|
714 |
+
struct arrow_proxy {
|
715 |
+
T value;
|
716 |
+
|
717 |
+
arrow_proxy(T &&value) : value(std::move(value)) { }
|
718 |
+
T *operator->() const { return &value; }
|
719 |
+
};
|
720 |
+
|
721 |
+
/// Lightweight iterator policy using just a simple pointer: see ``PySequence_Fast_ITEMS``
|
722 |
+
class sequence_fast_readonly {
|
723 |
+
protected:
|
724 |
+
using iterator_category = std::random_access_iterator_tag;
|
725 |
+
using value_type = handle;
|
726 |
+
using reference = const handle;
|
727 |
+
using pointer = arrow_proxy<const handle>;
|
728 |
+
|
729 |
+
sequence_fast_readonly(handle obj, ssize_t n) : ptr(PySequence_Fast_ITEMS(obj.ptr()) + n) { }
|
730 |
+
|
731 |
+
reference dereference() const { return *ptr; }
|
732 |
+
void increment() { ++ptr; }
|
733 |
+
void decrement() { --ptr; }
|
734 |
+
void advance(ssize_t n) { ptr += n; }
|
735 |
+
bool equal(const sequence_fast_readonly &b) const { return ptr == b.ptr; }
|
736 |
+
ssize_t distance_to(const sequence_fast_readonly &b) const { return ptr - b.ptr; }
|
737 |
+
|
738 |
+
private:
|
739 |
+
PyObject **ptr;
|
740 |
+
};
|
741 |
+
|
742 |
+
/// Full read and write access using the sequence protocol: see ``detail::sequence_accessor``
|
743 |
+
class sequence_slow_readwrite {
|
744 |
+
protected:
|
745 |
+
using iterator_category = std::random_access_iterator_tag;
|
746 |
+
using value_type = object;
|
747 |
+
using reference = sequence_accessor;
|
748 |
+
using pointer = arrow_proxy<const sequence_accessor>;
|
749 |
+
|
750 |
+
sequence_slow_readwrite(handle obj, ssize_t index) : obj(obj), index(index) { }
|
751 |
+
|
752 |
+
reference dereference() const { return {obj, static_cast<size_t>(index)}; }
|
753 |
+
void increment() { ++index; }
|
754 |
+
void decrement() { --index; }
|
755 |
+
void advance(ssize_t n) { index += n; }
|
756 |
+
bool equal(const sequence_slow_readwrite &b) const { return index == b.index; }
|
757 |
+
ssize_t distance_to(const sequence_slow_readwrite &b) const { return index - b.index; }
|
758 |
+
|
759 |
+
private:
|
760 |
+
handle obj;
|
761 |
+
ssize_t index;
|
762 |
+
};
|
763 |
+
|
764 |
+
/// Python's dictionary protocol permits this to be a forward iterator
|
765 |
+
class dict_readonly {
|
766 |
+
protected:
|
767 |
+
using iterator_category = std::forward_iterator_tag;
|
768 |
+
using value_type = std::pair<handle, handle>;
|
769 |
+
using reference = const value_type;
|
770 |
+
using pointer = arrow_proxy<const value_type>;
|
771 |
+
|
772 |
+
dict_readonly() = default;
|
773 |
+
dict_readonly(handle obj, ssize_t pos) : obj(obj), pos(pos) { increment(); }
|
774 |
+
|
775 |
+
reference dereference() const { return {key, value}; }
|
776 |
+
void increment() {
|
777 |
+
if (PyDict_Next(obj.ptr(), &pos, &key, &value) == 0) {
|
778 |
+
pos = -1;
|
779 |
+
}
|
780 |
+
}
|
781 |
+
bool equal(const dict_readonly &b) const { return pos == b.pos; }
|
782 |
+
|
783 |
+
private:
|
784 |
+
handle obj;
|
785 |
+
PyObject *key = nullptr, *value = nullptr;
|
786 |
+
ssize_t pos = -1;
|
787 |
+
};
|
788 |
+
PYBIND11_NAMESPACE_END(iterator_policies)
|
789 |
+
|
790 |
+
#if !defined(PYPY_VERSION)
|
791 |
+
using tuple_iterator = generic_iterator<iterator_policies::sequence_fast_readonly>;
|
792 |
+
using list_iterator = generic_iterator<iterator_policies::sequence_fast_readonly>;
|
793 |
+
#else
|
794 |
+
using tuple_iterator = generic_iterator<iterator_policies::sequence_slow_readwrite>;
|
795 |
+
using list_iterator = generic_iterator<iterator_policies::sequence_slow_readwrite>;
|
796 |
+
#endif
|
797 |
+
|
798 |
+
using sequence_iterator = generic_iterator<iterator_policies::sequence_slow_readwrite>;
|
799 |
+
using dict_iterator = generic_iterator<iterator_policies::dict_readonly>;
|
800 |
+
|
801 |
+
inline bool PyIterable_Check(PyObject *obj) {
|
802 |
+
PyObject *iter = PyObject_GetIter(obj);
|
803 |
+
if (iter) {
|
804 |
+
Py_DECREF(iter);
|
805 |
+
return true;
|
806 |
+
}
|
807 |
+
PyErr_Clear();
|
808 |
+
return false;
|
809 |
+
}
|
810 |
+
|
811 |
+
inline bool PyNone_Check(PyObject *o) { return o == Py_None; }
|
812 |
+
inline bool PyEllipsis_Check(PyObject *o) { return o == Py_Ellipsis; }
|
813 |
+
|
814 |
+
#ifdef PYBIND11_STR_LEGACY_PERMISSIVE
|
815 |
+
inline bool PyUnicode_Check_Permissive(PyObject *o) { return PyUnicode_Check(o) || PYBIND11_BYTES_CHECK(o); }
|
816 |
+
#define PYBIND11_STR_CHECK_FUN detail::PyUnicode_Check_Permissive
|
817 |
+
#else
|
818 |
+
#define PYBIND11_STR_CHECK_FUN PyUnicode_Check
|
819 |
+
#endif
|
820 |
+
|
821 |
+
inline bool PyStaticMethod_Check(PyObject *o) { return o->ob_type == &PyStaticMethod_Type; }
|
822 |
+
|
823 |
+
class kwargs_proxy : public handle {
|
824 |
+
public:
|
825 |
+
explicit kwargs_proxy(handle h) : handle(h) { }
|
826 |
+
};
|
827 |
+
|
828 |
+
class args_proxy : public handle {
|
829 |
+
public:
|
830 |
+
explicit args_proxy(handle h) : handle(h) { }
|
831 |
+
kwargs_proxy operator*() const { return kwargs_proxy(*this); }
|
832 |
+
};
|
833 |
+
|
834 |
+
/// Python argument categories (using PEP 448 terms)
|
835 |
+
template <typename T> using is_keyword = std::is_base_of<arg, T>;
|
836 |
+
template <typename T> using is_s_unpacking = std::is_same<args_proxy, T>; // * unpacking
|
837 |
+
template <typename T> using is_ds_unpacking = std::is_same<kwargs_proxy, T>; // ** unpacking
|
838 |
+
template <typename T> using is_positional = satisfies_none_of<T,
|
839 |
+
is_keyword, is_s_unpacking, is_ds_unpacking
|
840 |
+
>;
|
841 |
+
template <typename T> using is_keyword_or_ds = satisfies_any_of<T, is_keyword, is_ds_unpacking>;
|
842 |
+
|
843 |
+
// Call argument collector forward declarations
|
844 |
+
template <return_value_policy policy = return_value_policy::automatic_reference>
|
845 |
+
class simple_collector;
|
846 |
+
template <return_value_policy policy = return_value_policy::automatic_reference>
|
847 |
+
class unpacking_collector;
|
848 |
+
|
849 |
+
PYBIND11_NAMESPACE_END(detail)
|
850 |
+
|
851 |
+
// TODO: After the deprecated constructors are removed, this macro can be simplified by
|
852 |
+
// inheriting ctors: `using Parent::Parent`. It's not an option right now because
|
853 |
+
// the `using` statement triggers the parent deprecation warning even if the ctor
|
854 |
+
// isn't even used.
|
855 |
+
#define PYBIND11_OBJECT_COMMON(Name, Parent, CheckFun) \
|
856 |
+
public: \
|
857 |
+
PYBIND11_DEPRECATED("Use reinterpret_borrow<"#Name">() or reinterpret_steal<"#Name">()") \
|
858 |
+
Name(handle h, bool is_borrowed) : Parent(is_borrowed ? Parent(h, borrowed_t{}) : Parent(h, stolen_t{})) { } \
|
859 |
+
Name(handle h, borrowed_t) : Parent(h, borrowed_t{}) { } \
|
860 |
+
Name(handle h, stolen_t) : Parent(h, stolen_t{}) { } \
|
861 |
+
PYBIND11_DEPRECATED("Use py::isinstance<py::python_type>(obj) instead") \
|
862 |
+
bool check() const { return m_ptr != nullptr && (CheckFun(m_ptr) != 0); } \
|
863 |
+
static bool check_(handle h) { return h.ptr() != nullptr && CheckFun(h.ptr()); } \
|
864 |
+
template <typename Policy_> \
|
865 |
+
Name(const ::pybind11::detail::accessor<Policy_> &a) : Name(object(a)) { }
|
866 |
+
|
867 |
+
#define PYBIND11_OBJECT_CVT(Name, Parent, CheckFun, ConvertFun) \
|
868 |
+
PYBIND11_OBJECT_COMMON(Name, Parent, CheckFun) \
|
869 |
+
/* This is deliberately not 'explicit' to allow implicit conversion from object: */ \
|
870 |
+
Name(const object &o) \
|
871 |
+
: Parent(check_(o) ? o.inc_ref().ptr() : ConvertFun(o.ptr()), stolen_t{}) \
|
872 |
+
{ if (!m_ptr) throw error_already_set(); } \
|
873 |
+
Name(object &&o) \
|
874 |
+
: Parent(check_(o) ? o.release().ptr() : ConvertFun(o.ptr()), stolen_t{}) \
|
875 |
+
{ if (!m_ptr) throw error_already_set(); }
|
876 |
+
|
877 |
+
#define PYBIND11_OBJECT_CVT_DEFAULT(Name, Parent, CheckFun, ConvertFun) \
|
878 |
+
PYBIND11_OBJECT_CVT(Name, Parent, CheckFun, ConvertFun) \
|
879 |
+
Name() : Parent() { }
|
880 |
+
|
881 |
+
#define PYBIND11_OBJECT_CHECK_FAILED(Name, o_ptr) \
|
882 |
+
::pybind11::type_error("Object of type '" + \
|
883 |
+
::pybind11::detail::get_fully_qualified_tp_name(Py_TYPE(o_ptr)) + \
|
884 |
+
"' is not an instance of '" #Name "'")
|
885 |
+
|
886 |
+
#define PYBIND11_OBJECT(Name, Parent, CheckFun) \
|
887 |
+
PYBIND11_OBJECT_COMMON(Name, Parent, CheckFun) \
|
888 |
+
/* This is deliberately not 'explicit' to allow implicit conversion from object: */ \
|
889 |
+
Name(const object &o) : Parent(o) \
|
890 |
+
{ if (m_ptr && !check_(m_ptr)) throw PYBIND11_OBJECT_CHECK_FAILED(Name, m_ptr); } \
|
891 |
+
Name(object &&o) : Parent(std::move(o)) \
|
892 |
+
{ if (m_ptr && !check_(m_ptr)) throw PYBIND11_OBJECT_CHECK_FAILED(Name, m_ptr); }
|
893 |
+
|
894 |
+
#define PYBIND11_OBJECT_DEFAULT(Name, Parent, CheckFun) \
|
895 |
+
PYBIND11_OBJECT(Name, Parent, CheckFun) \
|
896 |
+
Name() : Parent() { }
|
897 |
+
|
898 |
+
/// \addtogroup pytypes
|
899 |
+
/// @{
|
900 |
+
|
901 |
+
/** \rst
|
902 |
+
Wraps a Python iterator so that it can also be used as a C++ input iterator
|
903 |
+
|
904 |
+
Caveat: copying an iterator does not (and cannot) clone the internal
|
905 |
+
state of the Python iterable. This also applies to the post-increment
|
906 |
+
operator. This iterator should only be used to retrieve the current
|
907 |
+
value using ``operator*()``.
|
908 |
+
\endrst */
|
909 |
+
class iterator : public object {
|
910 |
+
public:
|
911 |
+
using iterator_category = std::input_iterator_tag;
|
912 |
+
using difference_type = ssize_t;
|
913 |
+
using value_type = handle;
|
914 |
+
using reference = const handle;
|
915 |
+
using pointer = const handle *;
|
916 |
+
|
917 |
+
PYBIND11_OBJECT_DEFAULT(iterator, object, PyIter_Check)
|
918 |
+
|
919 |
+
iterator& operator++() {
|
920 |
+
advance();
|
921 |
+
return *this;
|
922 |
+
}
|
923 |
+
|
924 |
+
iterator operator++(int) {
|
925 |
+
auto rv = *this;
|
926 |
+
advance();
|
927 |
+
return rv;
|
928 |
+
}
|
929 |
+
|
930 |
+
reference operator*() const {
|
931 |
+
if (m_ptr && !value.ptr()) {
|
932 |
+
auto& self = const_cast<iterator &>(*this);
|
933 |
+
self.advance();
|
934 |
+
}
|
935 |
+
return value;
|
936 |
+
}
|
937 |
+
|
938 |
+
pointer operator->() const { operator*(); return &value; }
|
939 |
+
|
940 |
+
/** \rst
|
941 |
+
The value which marks the end of the iteration. ``it == iterator::sentinel()``
|
942 |
+
is equivalent to catching ``StopIteration`` in Python.
|
943 |
+
|
944 |
+
.. code-block:: cpp
|
945 |
+
|
946 |
+
void foo(py::iterator it) {
|
947 |
+
while (it != py::iterator::sentinel()) {
|
948 |
+
// use `*it`
|
949 |
+
++it;
|
950 |
+
}
|
951 |
+
}
|
952 |
+
\endrst */
|
953 |
+
static iterator sentinel() { return {}; }
|
954 |
+
|
955 |
+
friend bool operator==(const iterator &a, const iterator &b) { return a->ptr() == b->ptr(); }
|
956 |
+
friend bool operator!=(const iterator &a, const iterator &b) { return a->ptr() != b->ptr(); }
|
957 |
+
|
958 |
+
private:
|
959 |
+
void advance() {
|
960 |
+
value = reinterpret_steal<object>(PyIter_Next(m_ptr));
|
961 |
+
if (PyErr_Occurred()) { throw error_already_set(); }
|
962 |
+
}
|
963 |
+
|
964 |
+
private:
|
965 |
+
object value = {};
|
966 |
+
};
|
967 |
+
|
968 |
+
|
969 |
+
|
970 |
+
class type : public object {
|
971 |
+
public:
|
972 |
+
PYBIND11_OBJECT(type, object, PyType_Check)
|
973 |
+
|
974 |
+
/// Return a type handle from a handle or an object
|
975 |
+
static handle handle_of(handle h) { return handle((PyObject*) Py_TYPE(h.ptr())); }
|
976 |
+
|
977 |
+
/// Return a type object from a handle or an object
|
978 |
+
static type of(handle h) { return type(type::handle_of(h), borrowed_t{}); }
|
979 |
+
|
980 |
+
// Defined in pybind11/cast.h
|
981 |
+
/// Convert C++ type to handle if previously registered. Does not convert
|
982 |
+
/// standard types, like int, float. etc. yet.
|
983 |
+
/// See https://github.com/pybind/pybind11/issues/2486
|
984 |
+
template<typename T>
|
985 |
+
static handle handle_of();
|
986 |
+
|
987 |
+
/// Convert C++ type to type if previously registered. Does not convert
|
988 |
+
/// standard types, like int, float. etc. yet.
|
989 |
+
/// See https://github.com/pybind/pybind11/issues/2486
|
990 |
+
template<typename T>
|
991 |
+
static type of() {return type(type::handle_of<T>(), borrowed_t{}); }
|
992 |
+
};
|
993 |
+
|
994 |
+
class iterable : public object {
|
995 |
+
public:
|
996 |
+
PYBIND11_OBJECT_DEFAULT(iterable, object, detail::PyIterable_Check)
|
997 |
+
};
|
998 |
+
|
999 |
+
class bytes;
|
1000 |
+
|
1001 |
+
class str : public object {
|
1002 |
+
public:
|
1003 |
+
PYBIND11_OBJECT_CVT(str, object, PYBIND11_STR_CHECK_FUN, raw_str)
|
1004 |
+
|
1005 |
+
str(const char *c, size_t n)
|
1006 |
+
: object(PyUnicode_FromStringAndSize(c, (ssize_t) n), stolen_t{}) {
|
1007 |
+
if (!m_ptr) pybind11_fail("Could not allocate string object!");
|
1008 |
+
}
|
1009 |
+
|
1010 |
+
// 'explicit' is explicitly omitted from the following constructors to allow implicit conversion to py::str from C++ string-like objects
|
1011 |
+
str(const char *c = "")
|
1012 |
+
: object(PyUnicode_FromString(c), stolen_t{}) {
|
1013 |
+
if (!m_ptr) pybind11_fail("Could not allocate string object!");
|
1014 |
+
}
|
1015 |
+
|
1016 |
+
str(const std::string &s) : str(s.data(), s.size()) { }
|
1017 |
+
|
1018 |
+
explicit str(const bytes &b);
|
1019 |
+
|
1020 |
+
/** \rst
|
1021 |
+
Return a string representation of the object. This is analogous to
|
1022 |
+
the ``str()`` function in Python.
|
1023 |
+
\endrst */
|
1024 |
+
explicit str(handle h) : object(raw_str(h.ptr()), stolen_t{}) { if (!m_ptr) throw error_already_set(); }
|
1025 |
+
|
1026 |
+
operator std::string() const {
|
1027 |
+
object temp = *this;
|
1028 |
+
if (PyUnicode_Check(m_ptr)) {
|
1029 |
+
temp = reinterpret_steal<object>(PyUnicode_AsUTF8String(m_ptr));
|
1030 |
+
if (!temp)
|
1031 |
+
throw error_already_set();
|
1032 |
+
}
|
1033 |
+
char *buffer = nullptr;
|
1034 |
+
ssize_t length = 0;
|
1035 |
+
if (PYBIND11_BYTES_AS_STRING_AND_SIZE(temp.ptr(), &buffer, &length))
|
1036 |
+
pybind11_fail("Unable to extract string contents! (invalid type)");
|
1037 |
+
return std::string(buffer, (size_t) length);
|
1038 |
+
}
|
1039 |
+
|
1040 |
+
template <typename... Args>
|
1041 |
+
str format(Args &&...args) const {
|
1042 |
+
return attr("format")(std::forward<Args>(args)...);
|
1043 |
+
}
|
1044 |
+
|
1045 |
+
private:
|
1046 |
+
/// Return string representation -- always returns a new reference, even if already a str
|
1047 |
+
static PyObject *raw_str(PyObject *op) {
|
1048 |
+
PyObject *str_value = PyObject_Str(op);
|
1049 |
+
#if PY_MAJOR_VERSION < 3
|
1050 |
+
if (!str_value) throw error_already_set();
|
1051 |
+
PyObject *unicode = PyUnicode_FromEncodedObject(str_value, "utf-8", nullptr);
|
1052 |
+
Py_XDECREF(str_value); str_value = unicode;
|
1053 |
+
#endif
|
1054 |
+
return str_value;
|
1055 |
+
}
|
1056 |
+
};
|
1057 |
+
/// @} pytypes
|
1058 |
+
|
1059 |
+
inline namespace literals {
|
1060 |
+
/** \rst
|
1061 |
+
String literal version of `str`
|
1062 |
+
\endrst */
|
1063 |
+
inline str operator"" _s(const char *s, size_t size) { return {s, size}; }
|
1064 |
+
} // namespace literals
|
1065 |
+
|
1066 |
+
/// \addtogroup pytypes
|
1067 |
+
/// @{
|
1068 |
+
class bytes : public object {
|
1069 |
+
public:
|
1070 |
+
PYBIND11_OBJECT(bytes, object, PYBIND11_BYTES_CHECK)
|
1071 |
+
|
1072 |
+
// Allow implicit conversion:
|
1073 |
+
bytes(const char *c = "")
|
1074 |
+
: object(PYBIND11_BYTES_FROM_STRING(c), stolen_t{}) {
|
1075 |
+
if (!m_ptr) pybind11_fail("Could not allocate bytes object!");
|
1076 |
+
}
|
1077 |
+
|
1078 |
+
bytes(const char *c, size_t n)
|
1079 |
+
: object(PYBIND11_BYTES_FROM_STRING_AND_SIZE(c, (ssize_t) n), stolen_t{}) {
|
1080 |
+
if (!m_ptr) pybind11_fail("Could not allocate bytes object!");
|
1081 |
+
}
|
1082 |
+
|
1083 |
+
// Allow implicit conversion:
|
1084 |
+
bytes(const std::string &s) : bytes(s.data(), s.size()) { }
|
1085 |
+
|
1086 |
+
explicit bytes(const pybind11::str &s);
|
1087 |
+
|
1088 |
+
operator std::string() const {
|
1089 |
+
char *buffer = nullptr;
|
1090 |
+
ssize_t length = 0;
|
1091 |
+
if (PYBIND11_BYTES_AS_STRING_AND_SIZE(m_ptr, &buffer, &length))
|
1092 |
+
pybind11_fail("Unable to extract bytes contents!");
|
1093 |
+
return std::string(buffer, (size_t) length);
|
1094 |
+
}
|
1095 |
+
};
|
1096 |
+
// Note: breathe >= 4.17.0 will fail to build docs if the below two constructors
|
1097 |
+
// are included in the doxygen group; close here and reopen after as a workaround
|
1098 |
+
/// @} pytypes
|
1099 |
+
|
1100 |
+
inline bytes::bytes(const pybind11::str &s) {
|
1101 |
+
object temp = s;
|
1102 |
+
if (PyUnicode_Check(s.ptr())) {
|
1103 |
+
temp = reinterpret_steal<object>(PyUnicode_AsUTF8String(s.ptr()));
|
1104 |
+
if (!temp)
|
1105 |
+
pybind11_fail("Unable to extract string contents! (encoding issue)");
|
1106 |
+
}
|
1107 |
+
char *buffer = nullptr;
|
1108 |
+
ssize_t length = 0;
|
1109 |
+
if (PYBIND11_BYTES_AS_STRING_AND_SIZE(temp.ptr(), &buffer, &length))
|
1110 |
+
pybind11_fail("Unable to extract string contents! (invalid type)");
|
1111 |
+
auto obj = reinterpret_steal<object>(PYBIND11_BYTES_FROM_STRING_AND_SIZE(buffer, length));
|
1112 |
+
if (!obj)
|
1113 |
+
pybind11_fail("Could not allocate bytes object!");
|
1114 |
+
m_ptr = obj.release().ptr();
|
1115 |
+
}
|
1116 |
+
|
1117 |
+
inline str::str(const bytes& b) {
|
1118 |
+
char *buffer = nullptr;
|
1119 |
+
ssize_t length = 0;
|
1120 |
+
if (PYBIND11_BYTES_AS_STRING_AND_SIZE(b.ptr(), &buffer, &length))
|
1121 |
+
pybind11_fail("Unable to extract bytes contents!");
|
1122 |
+
auto obj = reinterpret_steal<object>(PyUnicode_FromStringAndSize(buffer, (ssize_t) length));
|
1123 |
+
if (!obj)
|
1124 |
+
pybind11_fail("Could not allocate string object!");
|
1125 |
+
m_ptr = obj.release().ptr();
|
1126 |
+
}
|
1127 |
+
|
1128 |
+
/// \addtogroup pytypes
|
1129 |
+
/// @{
|
1130 |
+
class bytearray : public object {
|
1131 |
+
public:
|
1132 |
+
PYBIND11_OBJECT_CVT(bytearray, object, PyByteArray_Check, PyByteArray_FromObject)
|
1133 |
+
|
1134 |
+
bytearray(const char *c, size_t n)
|
1135 |
+
: object(PyByteArray_FromStringAndSize(c, (ssize_t) n), stolen_t{}) {
|
1136 |
+
if (!m_ptr) pybind11_fail("Could not allocate bytearray object!");
|
1137 |
+
}
|
1138 |
+
|
1139 |
+
bytearray()
|
1140 |
+
: bytearray("", 0) {}
|
1141 |
+
|
1142 |
+
explicit bytearray(const std::string &s) : bytearray(s.data(), s.size()) { }
|
1143 |
+
|
1144 |
+
size_t size() const { return static_cast<size_t>(PyByteArray_Size(m_ptr)); }
|
1145 |
+
|
1146 |
+
explicit operator std::string() const {
|
1147 |
+
char *buffer = PyByteArray_AS_STRING(m_ptr);
|
1148 |
+
ssize_t size = PyByteArray_GET_SIZE(m_ptr);
|
1149 |
+
return std::string(buffer, static_cast<size_t>(size));
|
1150 |
+
}
|
1151 |
+
};
|
1152 |
+
// Note: breathe >= 4.17.0 will fail to build docs if the below two constructors
|
1153 |
+
// are included in the doxygen group; close here and reopen after as a workaround
|
1154 |
+
/// @} pytypes
|
1155 |
+
|
1156 |
+
/// \addtogroup pytypes
|
1157 |
+
/// @{
|
1158 |
+
class none : public object {
|
1159 |
+
public:
|
1160 |
+
PYBIND11_OBJECT(none, object, detail::PyNone_Check)
|
1161 |
+
none() : object(Py_None, borrowed_t{}) { }
|
1162 |
+
};
|
1163 |
+
|
1164 |
+
class ellipsis : public object {
|
1165 |
+
public:
|
1166 |
+
PYBIND11_OBJECT(ellipsis, object, detail::PyEllipsis_Check)
|
1167 |
+
ellipsis() : object(Py_Ellipsis, borrowed_t{}) { }
|
1168 |
+
};
|
1169 |
+
|
1170 |
+
class bool_ : public object {
|
1171 |
+
public:
|
1172 |
+
PYBIND11_OBJECT_CVT(bool_, object, PyBool_Check, raw_bool)
|
1173 |
+
bool_() : object(Py_False, borrowed_t{}) { }
|
1174 |
+
// Allow implicit conversion from and to `bool`:
|
1175 |
+
bool_(bool value) : object(value ? Py_True : Py_False, borrowed_t{}) { }
|
1176 |
+
operator bool() const { return (m_ptr != nullptr) && PyLong_AsLong(m_ptr) != 0; }
|
1177 |
+
|
1178 |
+
private:
|
1179 |
+
/// Return the truth value of an object -- always returns a new reference
|
1180 |
+
static PyObject *raw_bool(PyObject *op) {
|
1181 |
+
const auto value = PyObject_IsTrue(op);
|
1182 |
+
if (value == -1) return nullptr;
|
1183 |
+
return handle(value != 0 ? Py_True : Py_False).inc_ref().ptr();
|
1184 |
+
}
|
1185 |
+
};
|
1186 |
+
|
1187 |
+
PYBIND11_NAMESPACE_BEGIN(detail)
|
1188 |
+
// Converts a value to the given unsigned type. If an error occurs, you get back (Unsigned) -1;
|
1189 |
+
// otherwise you get back the unsigned long or unsigned long long value cast to (Unsigned).
|
1190 |
+
// (The distinction is critically important when casting a returned -1 error value to some other
|
1191 |
+
// unsigned type: (A)-1 != (B)-1 when A and B are unsigned types of different sizes).
|
1192 |
+
template <typename Unsigned>
|
1193 |
+
Unsigned as_unsigned(PyObject *o) {
|
1194 |
+
if (sizeof(Unsigned) <= sizeof(unsigned long)
|
1195 |
+
#if PY_VERSION_HEX < 0x03000000
|
1196 |
+
|| PyInt_Check(o)
|
1197 |
+
#endif
|
1198 |
+
) {
|
1199 |
+
unsigned long v = PyLong_AsUnsignedLong(o);
|
1200 |
+
return v == (unsigned long) -1 && PyErr_Occurred() ? (Unsigned) -1 : (Unsigned) v;
|
1201 |
+
}
|
1202 |
+
unsigned long long v = PyLong_AsUnsignedLongLong(o);
|
1203 |
+
return v == (unsigned long long) -1 && PyErr_Occurred() ? (Unsigned) -1 : (Unsigned) v;
|
1204 |
+
}
|
1205 |
+
PYBIND11_NAMESPACE_END(detail)
|
1206 |
+
|
1207 |
+
class int_ : public object {
|
1208 |
+
public:
|
1209 |
+
PYBIND11_OBJECT_CVT(int_, object, PYBIND11_LONG_CHECK, PyNumber_Long)
|
1210 |
+
int_() : object(PyLong_FromLong(0), stolen_t{}) { }
|
1211 |
+
// Allow implicit conversion from C++ integral types:
|
1212 |
+
template <typename T,
|
1213 |
+
detail::enable_if_t<std::is_integral<T>::value, int> = 0>
|
1214 |
+
int_(T value) {
|
1215 |
+
if (sizeof(T) <= sizeof(long)) {
|
1216 |
+
if (std::is_signed<T>::value)
|
1217 |
+
m_ptr = PyLong_FromLong((long) value);
|
1218 |
+
else
|
1219 |
+
m_ptr = PyLong_FromUnsignedLong((unsigned long) value);
|
1220 |
+
} else {
|
1221 |
+
if (std::is_signed<T>::value)
|
1222 |
+
m_ptr = PyLong_FromLongLong((long long) value);
|
1223 |
+
else
|
1224 |
+
m_ptr = PyLong_FromUnsignedLongLong((unsigned long long) value);
|
1225 |
+
}
|
1226 |
+
if (!m_ptr) pybind11_fail("Could not allocate int object!");
|
1227 |
+
}
|
1228 |
+
|
1229 |
+
template <typename T,
|
1230 |
+
detail::enable_if_t<std::is_integral<T>::value, int> = 0>
|
1231 |
+
operator T() const {
|
1232 |
+
return std::is_unsigned<T>::value
|
1233 |
+
? detail::as_unsigned<T>(m_ptr)
|
1234 |
+
: sizeof(T) <= sizeof(long)
|
1235 |
+
? (T) PyLong_AsLong(m_ptr)
|
1236 |
+
: (T) PYBIND11_LONG_AS_LONGLONG(m_ptr);
|
1237 |
+
}
|
1238 |
+
};
|
1239 |
+
|
1240 |
+
class float_ : public object {
|
1241 |
+
public:
|
1242 |
+
PYBIND11_OBJECT_CVT(float_, object, PyFloat_Check, PyNumber_Float)
|
1243 |
+
// Allow implicit conversion from float/double:
|
1244 |
+
float_(float value) : object(PyFloat_FromDouble((double) value), stolen_t{}) {
|
1245 |
+
if (!m_ptr) pybind11_fail("Could not allocate float object!");
|
1246 |
+
}
|
1247 |
+
float_(double value = .0) : object(PyFloat_FromDouble((double) value), stolen_t{}) {
|
1248 |
+
if (!m_ptr) pybind11_fail("Could not allocate float object!");
|
1249 |
+
}
|
1250 |
+
operator float() const { return (float) PyFloat_AsDouble(m_ptr); }
|
1251 |
+
operator double() const { return (double) PyFloat_AsDouble(m_ptr); }
|
1252 |
+
};
|
1253 |
+
|
1254 |
+
class weakref : public object {
|
1255 |
+
public:
|
1256 |
+
PYBIND11_OBJECT_CVT_DEFAULT(weakref, object, PyWeakref_Check, raw_weakref)
|
1257 |
+
explicit weakref(handle obj, handle callback = {})
|
1258 |
+
: object(PyWeakref_NewRef(obj.ptr(), callback.ptr()), stolen_t{}) {
|
1259 |
+
if (!m_ptr) pybind11_fail("Could not allocate weak reference!");
|
1260 |
+
}
|
1261 |
+
|
1262 |
+
private:
|
1263 |
+
static PyObject *raw_weakref(PyObject *o) {
|
1264 |
+
return PyWeakref_NewRef(o, nullptr);
|
1265 |
+
}
|
1266 |
+
};
|
1267 |
+
|
1268 |
+
class slice : public object {
|
1269 |
+
public:
|
1270 |
+
PYBIND11_OBJECT_DEFAULT(slice, object, PySlice_Check)
|
1271 |
+
slice(ssize_t start_, ssize_t stop_, ssize_t step_) {
|
1272 |
+
int_ start(start_), stop(stop_), step(step_);
|
1273 |
+
m_ptr = PySlice_New(start.ptr(), stop.ptr(), step.ptr());
|
1274 |
+
if (!m_ptr) pybind11_fail("Could not allocate slice object!");
|
1275 |
+
}
|
1276 |
+
bool compute(size_t length, size_t *start, size_t *stop, size_t *step,
|
1277 |
+
size_t *slicelength) const {
|
1278 |
+
return PySlice_GetIndicesEx((PYBIND11_SLICE_OBJECT *) m_ptr,
|
1279 |
+
(ssize_t) length, (ssize_t *) start,
|
1280 |
+
(ssize_t *) stop, (ssize_t *) step,
|
1281 |
+
(ssize_t *) slicelength) == 0;
|
1282 |
+
}
|
1283 |
+
bool compute(ssize_t length, ssize_t *start, ssize_t *stop, ssize_t *step,
|
1284 |
+
ssize_t *slicelength) const {
|
1285 |
+
return PySlice_GetIndicesEx((PYBIND11_SLICE_OBJECT *) m_ptr,
|
1286 |
+
length, start,
|
1287 |
+
stop, step,
|
1288 |
+
slicelength) == 0;
|
1289 |
+
}
|
1290 |
+
};
|
1291 |
+
|
1292 |
+
class capsule : public object {
|
1293 |
+
public:
|
1294 |
+
PYBIND11_OBJECT_DEFAULT(capsule, object, PyCapsule_CheckExact)
|
1295 |
+
PYBIND11_DEPRECATED("Use reinterpret_borrow<capsule>() or reinterpret_steal<capsule>()")
|
1296 |
+
capsule(PyObject *ptr, bool is_borrowed) : object(is_borrowed ? object(ptr, borrowed_t{}) : object(ptr, stolen_t{})) { }
|
1297 |
+
|
1298 |
+
explicit capsule(const void *value, const char *name = nullptr, void (*destructor)(PyObject *) = nullptr)
|
1299 |
+
: object(PyCapsule_New(const_cast<void *>(value), name, destructor), stolen_t{}) {
|
1300 |
+
if (!m_ptr)
|
1301 |
+
pybind11_fail("Could not allocate capsule object!");
|
1302 |
+
}
|
1303 |
+
|
1304 |
+
PYBIND11_DEPRECATED("Please pass a destructor that takes a void pointer as input")
|
1305 |
+
capsule(const void *value, void (*destruct)(PyObject *))
|
1306 |
+
: object(PyCapsule_New(const_cast<void*>(value), nullptr, destruct), stolen_t{}) {
|
1307 |
+
if (!m_ptr)
|
1308 |
+
pybind11_fail("Could not allocate capsule object!");
|
1309 |
+
}
|
1310 |
+
|
1311 |
+
capsule(const void *value, void (*destructor)(void *)) {
|
1312 |
+
m_ptr = PyCapsule_New(const_cast<void *>(value), nullptr, [](PyObject *o) {
|
1313 |
+
auto destructor = reinterpret_cast<void (*)(void *)>(PyCapsule_GetContext(o));
|
1314 |
+
void *ptr = PyCapsule_GetPointer(o, nullptr);
|
1315 |
+
destructor(ptr);
|
1316 |
+
});
|
1317 |
+
|
1318 |
+
if (!m_ptr)
|
1319 |
+
pybind11_fail("Could not allocate capsule object!");
|
1320 |
+
|
1321 |
+
if (PyCapsule_SetContext(m_ptr, (void *) destructor) != 0)
|
1322 |
+
pybind11_fail("Could not set capsule context!");
|
1323 |
+
}
|
1324 |
+
|
1325 |
+
capsule(void (*destructor)()) {
|
1326 |
+
m_ptr = PyCapsule_New(reinterpret_cast<void *>(destructor), nullptr, [](PyObject *o) {
|
1327 |
+
auto destructor = reinterpret_cast<void (*)()>(PyCapsule_GetPointer(o, nullptr));
|
1328 |
+
destructor();
|
1329 |
+
});
|
1330 |
+
|
1331 |
+
if (!m_ptr)
|
1332 |
+
pybind11_fail("Could not allocate capsule object!");
|
1333 |
+
}
|
1334 |
+
|
1335 |
+
template <typename T> operator T *() const {
|
1336 |
+
return get_pointer<T>();
|
1337 |
+
}
|
1338 |
+
|
1339 |
+
/// Get the pointer the capsule holds.
|
1340 |
+
template<typename T = void>
|
1341 |
+
T* get_pointer() const {
|
1342 |
+
auto name = this->name();
|
1343 |
+
T *result = static_cast<T *>(PyCapsule_GetPointer(m_ptr, name));
|
1344 |
+
if (!result) pybind11_fail("Unable to extract capsule contents!");
|
1345 |
+
return result;
|
1346 |
+
}
|
1347 |
+
|
1348 |
+
/// Replaces a capsule's pointer *without* calling the destructor on the existing one.
|
1349 |
+
void set_pointer(const void *value) {
|
1350 |
+
if (PyCapsule_SetPointer(m_ptr, const_cast<void *>(value)) != 0)
|
1351 |
+
pybind11_fail("Could not set capsule pointer");
|
1352 |
+
}
|
1353 |
+
|
1354 |
+
const char *name() const { return PyCapsule_GetName(m_ptr); }
|
1355 |
+
};
|
1356 |
+
|
1357 |
+
class tuple : public object {
|
1358 |
+
public:
|
1359 |
+
PYBIND11_OBJECT_CVT(tuple, object, PyTuple_Check, PySequence_Tuple)
|
1360 |
+
explicit tuple(size_t size = 0) : object(PyTuple_New((ssize_t) size), stolen_t{}) {
|
1361 |
+
if (!m_ptr) pybind11_fail("Could not allocate tuple object!");
|
1362 |
+
}
|
1363 |
+
size_t size() const { return (size_t) PyTuple_Size(m_ptr); }
|
1364 |
+
bool empty() const { return size() == 0; }
|
1365 |
+
detail::tuple_accessor operator[](size_t index) const { return {*this, index}; }
|
1366 |
+
detail::item_accessor operator[](handle h) const { return object::operator[](h); }
|
1367 |
+
detail::tuple_iterator begin() const { return {*this, 0}; }
|
1368 |
+
detail::tuple_iterator end() const { return {*this, PyTuple_GET_SIZE(m_ptr)}; }
|
1369 |
+
};
|
1370 |
+
|
1371 |
+
// We need to put this into a separate function because the Intel compiler
|
1372 |
+
// fails to compile enable_if_t<all_of<is_keyword_or_ds<Args>...>::value> part below
|
1373 |
+
// (tested with ICC 2021.1 Beta 20200827).
|
1374 |
+
template <typename... Args>
|
1375 |
+
constexpr bool args_are_all_keyword_or_ds()
|
1376 |
+
{
|
1377 |
+
return detail::all_of<detail::is_keyword_or_ds<Args>...>::value;
|
1378 |
+
}
|
1379 |
+
|
1380 |
+
class dict : public object {
|
1381 |
+
public:
|
1382 |
+
PYBIND11_OBJECT_CVT(dict, object, PyDict_Check, raw_dict)
|
1383 |
+
dict() : object(PyDict_New(), stolen_t{}) {
|
1384 |
+
if (!m_ptr) pybind11_fail("Could not allocate dict object!");
|
1385 |
+
}
|
1386 |
+
template <typename... Args,
|
1387 |
+
typename = detail::enable_if_t<args_are_all_keyword_or_ds<Args...>()>,
|
1388 |
+
// MSVC workaround: it can't compile an out-of-line definition, so defer the collector
|
1389 |
+
typename collector = detail::deferred_t<detail::unpacking_collector<>, Args...>>
|
1390 |
+
explicit dict(Args &&...args) : dict(collector(std::forward<Args>(args)...).kwargs()) { }
|
1391 |
+
|
1392 |
+
size_t size() const { return (size_t) PyDict_Size(m_ptr); }
|
1393 |
+
bool empty() const { return size() == 0; }
|
1394 |
+
detail::dict_iterator begin() const { return {*this, 0}; }
|
1395 |
+
detail::dict_iterator end() const { return {}; }
|
1396 |
+
void clear() const { PyDict_Clear(ptr()); }
|
1397 |
+
template <typename T> bool contains(T &&key) const {
|
1398 |
+
return PyDict_Contains(m_ptr, detail::object_or_cast(std::forward<T>(key)).ptr()) == 1;
|
1399 |
+
}
|
1400 |
+
|
1401 |
+
private:
|
1402 |
+
/// Call the `dict` Python type -- always returns a new reference
|
1403 |
+
static PyObject *raw_dict(PyObject *op) {
|
1404 |
+
if (PyDict_Check(op))
|
1405 |
+
return handle(op).inc_ref().ptr();
|
1406 |
+
return PyObject_CallFunctionObjArgs((PyObject *) &PyDict_Type, op, nullptr);
|
1407 |
+
}
|
1408 |
+
};
|
1409 |
+
|
1410 |
+
class sequence : public object {
|
1411 |
+
public:
|
1412 |
+
PYBIND11_OBJECT_DEFAULT(sequence, object, PySequence_Check)
|
1413 |
+
size_t size() const {
|
1414 |
+
ssize_t result = PySequence_Size(m_ptr);
|
1415 |
+
if (result == -1)
|
1416 |
+
throw error_already_set();
|
1417 |
+
return (size_t) result;
|
1418 |
+
}
|
1419 |
+
bool empty() const { return size() == 0; }
|
1420 |
+
detail::sequence_accessor operator[](size_t index) const { return {*this, index}; }
|
1421 |
+
detail::item_accessor operator[](handle h) const { return object::operator[](h); }
|
1422 |
+
detail::sequence_iterator begin() const { return {*this, 0}; }
|
1423 |
+
detail::sequence_iterator end() const { return {*this, PySequence_Size(m_ptr)}; }
|
1424 |
+
};
|
1425 |
+
|
1426 |
+
class list : public object {
|
1427 |
+
public:
|
1428 |
+
PYBIND11_OBJECT_CVT(list, object, PyList_Check, PySequence_List)
|
1429 |
+
explicit list(size_t size = 0) : object(PyList_New((ssize_t) size), stolen_t{}) {
|
1430 |
+
if (!m_ptr) pybind11_fail("Could not allocate list object!");
|
1431 |
+
}
|
1432 |
+
size_t size() const { return (size_t) PyList_Size(m_ptr); }
|
1433 |
+
bool empty() const { return size() == 0; }
|
1434 |
+
detail::list_accessor operator[](size_t index) const { return {*this, index}; }
|
1435 |
+
detail::item_accessor operator[](handle h) const { return object::operator[](h); }
|
1436 |
+
detail::list_iterator begin() const { return {*this, 0}; }
|
1437 |
+
detail::list_iterator end() const { return {*this, PyList_GET_SIZE(m_ptr)}; }
|
1438 |
+
template <typename T> void append(T &&val) const {
|
1439 |
+
PyList_Append(m_ptr, detail::object_or_cast(std::forward<T>(val)).ptr());
|
1440 |
+
}
|
1441 |
+
template <typename T> void insert(size_t index, T &&val) const {
|
1442 |
+
PyList_Insert(m_ptr, static_cast<ssize_t>(index),
|
1443 |
+
detail::object_or_cast(std::forward<T>(val)).ptr());
|
1444 |
+
}
|
1445 |
+
};
|
1446 |
+
|
1447 |
+
class args : public tuple { PYBIND11_OBJECT_DEFAULT(args, tuple, PyTuple_Check) };
|
1448 |
+
class kwargs : public dict { PYBIND11_OBJECT_DEFAULT(kwargs, dict, PyDict_Check) };
|
1449 |
+
|
1450 |
+
class set : public object {
|
1451 |
+
public:
|
1452 |
+
PYBIND11_OBJECT_CVT(set, object, PySet_Check, PySet_New)
|
1453 |
+
set() : object(PySet_New(nullptr), stolen_t{}) {
|
1454 |
+
if (!m_ptr) pybind11_fail("Could not allocate set object!");
|
1455 |
+
}
|
1456 |
+
size_t size() const { return (size_t) PySet_Size(m_ptr); }
|
1457 |
+
bool empty() const { return size() == 0; }
|
1458 |
+
template <typename T> bool add(T &&val) const {
|
1459 |
+
return PySet_Add(m_ptr, detail::object_or_cast(std::forward<T>(val)).ptr()) == 0;
|
1460 |
+
}
|
1461 |
+
void clear() const { PySet_Clear(m_ptr); }
|
1462 |
+
template <typename T> bool contains(T &&val) const {
|
1463 |
+
return PySet_Contains(m_ptr, detail::object_or_cast(std::forward<T>(val)).ptr()) == 1;
|
1464 |
+
}
|
1465 |
+
};
|
1466 |
+
|
1467 |
+
class function : public object {
|
1468 |
+
public:
|
1469 |
+
PYBIND11_OBJECT_DEFAULT(function, object, PyCallable_Check)
|
1470 |
+
handle cpp_function() const {
|
1471 |
+
handle fun = detail::get_function(m_ptr);
|
1472 |
+
if (fun && PyCFunction_Check(fun.ptr()))
|
1473 |
+
return fun;
|
1474 |
+
return handle();
|
1475 |
+
}
|
1476 |
+
bool is_cpp_function() const { return (bool) cpp_function(); }
|
1477 |
+
};
|
1478 |
+
|
1479 |
+
class staticmethod : public object {
|
1480 |
+
public:
|
1481 |
+
PYBIND11_OBJECT_CVT(staticmethod, object, detail::PyStaticMethod_Check, PyStaticMethod_New)
|
1482 |
+
};
|
1483 |
+
|
1484 |
+
class buffer : public object {
|
1485 |
+
public:
|
1486 |
+
PYBIND11_OBJECT_DEFAULT(buffer, object, PyObject_CheckBuffer)
|
1487 |
+
|
1488 |
+
buffer_info request(bool writable = false) const {
|
1489 |
+
int flags = PyBUF_STRIDES | PyBUF_FORMAT;
|
1490 |
+
if (writable) flags |= PyBUF_WRITABLE;
|
1491 |
+
auto *view = new Py_buffer();
|
1492 |
+
if (PyObject_GetBuffer(m_ptr, view, flags) != 0) {
|
1493 |
+
delete view;
|
1494 |
+
throw error_already_set();
|
1495 |
+
}
|
1496 |
+
return buffer_info(view);
|
1497 |
+
}
|
1498 |
+
};
|
1499 |
+
|
1500 |
+
class memoryview : public object {
|
1501 |
+
public:
|
1502 |
+
PYBIND11_OBJECT_CVT(memoryview, object, PyMemoryView_Check, PyMemoryView_FromObject)
|
1503 |
+
|
1504 |
+
/** \rst
|
1505 |
+
Creates ``memoryview`` from ``buffer_info``.
|
1506 |
+
|
1507 |
+
``buffer_info`` must be created from ``buffer::request()``. Otherwise
|
1508 |
+
throws an exception.
|
1509 |
+
|
1510 |
+
For creating a ``memoryview`` from objects that support buffer protocol,
|
1511 |
+
use ``memoryview(const object& obj)`` instead of this constructor.
|
1512 |
+
\endrst */
|
1513 |
+
explicit memoryview(const buffer_info& info) {
|
1514 |
+
if (!info.view())
|
1515 |
+
pybind11_fail("Prohibited to create memoryview without Py_buffer");
|
1516 |
+
// Note: PyMemoryView_FromBuffer never increments obj reference.
|
1517 |
+
m_ptr = (info.view()->obj) ?
|
1518 |
+
PyMemoryView_FromObject(info.view()->obj) :
|
1519 |
+
PyMemoryView_FromBuffer(info.view());
|
1520 |
+
if (!m_ptr)
|
1521 |
+
pybind11_fail("Unable to create memoryview from buffer descriptor");
|
1522 |
+
}
|
1523 |
+
|
1524 |
+
/** \rst
|
1525 |
+
Creates ``memoryview`` from static buffer.
|
1526 |
+
|
1527 |
+
This method is meant for providing a ``memoryview`` for C/C++ buffer not
|
1528 |
+
managed by Python. The caller is responsible for managing the lifetime
|
1529 |
+
of ``ptr`` and ``format``, which MUST outlive the memoryview constructed
|
1530 |
+
here.
|
1531 |
+
|
1532 |
+
See also: Python C API documentation for `PyMemoryView_FromBuffer`_.
|
1533 |
+
|
1534 |
+
.. _PyMemoryView_FromBuffer: https://docs.python.org/c-api/memoryview.html#c.PyMemoryView_FromBuffer
|
1535 |
+
|
1536 |
+
:param ptr: Pointer to the buffer.
|
1537 |
+
:param itemsize: Byte size of an element.
|
1538 |
+
:param format: Pointer to the null-terminated format string. For
|
1539 |
+
homogeneous Buffers, this should be set to
|
1540 |
+
``format_descriptor<T>::value``.
|
1541 |
+
:param shape: Shape of the tensor (1 entry per dimension).
|
1542 |
+
:param strides: Number of bytes between adjacent entries (for each
|
1543 |
+
per dimension).
|
1544 |
+
:param readonly: Flag to indicate if the underlying storage may be
|
1545 |
+
written to.
|
1546 |
+
\endrst */
|
1547 |
+
static memoryview from_buffer(
|
1548 |
+
void *ptr, ssize_t itemsize, const char *format,
|
1549 |
+
detail::any_container<ssize_t> shape,
|
1550 |
+
detail::any_container<ssize_t> strides, bool readonly = false);
|
1551 |
+
|
1552 |
+
static memoryview from_buffer(
|
1553 |
+
const void *ptr, ssize_t itemsize, const char *format,
|
1554 |
+
detail::any_container<ssize_t> shape,
|
1555 |
+
detail::any_container<ssize_t> strides) {
|
1556 |
+
return memoryview::from_buffer(
|
1557 |
+
const_cast<void *>(ptr), itemsize, format, std::move(shape), std::move(strides), true);
|
1558 |
+
}
|
1559 |
+
|
1560 |
+
template<typename T>
|
1561 |
+
static memoryview from_buffer(
|
1562 |
+
T *ptr, detail::any_container<ssize_t> shape,
|
1563 |
+
detail::any_container<ssize_t> strides, bool readonly = false) {
|
1564 |
+
return memoryview::from_buffer(
|
1565 |
+
reinterpret_cast<void*>(ptr), sizeof(T),
|
1566 |
+
format_descriptor<T>::value, shape, strides, readonly);
|
1567 |
+
}
|
1568 |
+
|
1569 |
+
template<typename T>
|
1570 |
+
static memoryview from_buffer(
|
1571 |
+
const T *ptr, detail::any_container<ssize_t> shape,
|
1572 |
+
detail::any_container<ssize_t> strides) {
|
1573 |
+
return memoryview::from_buffer(
|
1574 |
+
const_cast<T*>(ptr), shape, strides, true);
|
1575 |
+
}
|
1576 |
+
|
1577 |
+
#if PY_MAJOR_VERSION >= 3
|
1578 |
+
/** \rst
|
1579 |
+
Creates ``memoryview`` from static memory.
|
1580 |
+
|
1581 |
+
This method is meant for providing a ``memoryview`` for C/C++ buffer not
|
1582 |
+
managed by Python. The caller is responsible for managing the lifetime
|
1583 |
+
of ``mem``, which MUST outlive the memoryview constructed here.
|
1584 |
+
|
1585 |
+
This method is not available in Python 2.
|
1586 |
+
|
1587 |
+
See also: Python C API documentation for `PyMemoryView_FromBuffer`_.
|
1588 |
+
|
1589 |
+
.. _PyMemoryView_FromMemory: https://docs.python.org/c-api/memoryview.html#c.PyMemoryView_FromMemory
|
1590 |
+
\endrst */
|
1591 |
+
static memoryview from_memory(void *mem, ssize_t size, bool readonly = false) {
|
1592 |
+
PyObject* ptr = PyMemoryView_FromMemory(
|
1593 |
+
reinterpret_cast<char*>(mem), size,
|
1594 |
+
(readonly) ? PyBUF_READ : PyBUF_WRITE);
|
1595 |
+
if (!ptr)
|
1596 |
+
pybind11_fail("Could not allocate memoryview object!");
|
1597 |
+
return memoryview(object(ptr, stolen_t{}));
|
1598 |
+
}
|
1599 |
+
|
1600 |
+
static memoryview from_memory(const void *mem, ssize_t size) {
|
1601 |
+
return memoryview::from_memory(const_cast<void*>(mem), size, true);
|
1602 |
+
}
|
1603 |
+
#endif
|
1604 |
+
};
|
1605 |
+
|
1606 |
+
#ifndef DOXYGEN_SHOULD_SKIP_THIS
|
1607 |
+
inline memoryview memoryview::from_buffer(
|
1608 |
+
void *ptr, ssize_t itemsize, const char* format,
|
1609 |
+
detail::any_container<ssize_t> shape,
|
1610 |
+
detail::any_container<ssize_t> strides, bool readonly) {
|
1611 |
+
size_t ndim = shape->size();
|
1612 |
+
if (ndim != strides->size())
|
1613 |
+
pybind11_fail("memoryview: shape length doesn't match strides length");
|
1614 |
+
ssize_t size = ndim != 0u ? 1 : 0;
|
1615 |
+
for (size_t i = 0; i < ndim; ++i)
|
1616 |
+
size *= (*shape)[i];
|
1617 |
+
Py_buffer view;
|
1618 |
+
view.buf = ptr;
|
1619 |
+
view.obj = nullptr;
|
1620 |
+
view.len = size * itemsize;
|
1621 |
+
view.readonly = static_cast<int>(readonly);
|
1622 |
+
view.itemsize = itemsize;
|
1623 |
+
view.format = const_cast<char*>(format);
|
1624 |
+
view.ndim = static_cast<int>(ndim);
|
1625 |
+
view.shape = shape->data();
|
1626 |
+
view.strides = strides->data();
|
1627 |
+
view.suboffsets = nullptr;
|
1628 |
+
view.internal = nullptr;
|
1629 |
+
PyObject* obj = PyMemoryView_FromBuffer(&view);
|
1630 |
+
if (!obj)
|
1631 |
+
throw error_already_set();
|
1632 |
+
return memoryview(object(obj, stolen_t{}));
|
1633 |
+
}
|
1634 |
+
#endif // DOXYGEN_SHOULD_SKIP_THIS
|
1635 |
+
/// @} pytypes
|
1636 |
+
|
1637 |
+
/// \addtogroup python_builtins
|
1638 |
+
/// @{
|
1639 |
+
|
1640 |
+
/// Get the length of a Python object.
|
1641 |
+
inline size_t len(handle h) {
|
1642 |
+
ssize_t result = PyObject_Length(h.ptr());
|
1643 |
+
if (result < 0)
|
1644 |
+
throw error_already_set();
|
1645 |
+
return (size_t) result;
|
1646 |
+
}
|
1647 |
+
|
1648 |
+
/// Get the length hint of a Python object.
|
1649 |
+
/// Returns 0 when this cannot be determined.
|
1650 |
+
inline size_t len_hint(handle h) {
|
1651 |
+
#if PY_VERSION_HEX >= 0x03040000
|
1652 |
+
ssize_t result = PyObject_LengthHint(h.ptr(), 0);
|
1653 |
+
#else
|
1654 |
+
ssize_t result = PyObject_Length(h.ptr());
|
1655 |
+
#endif
|
1656 |
+
if (result < 0) {
|
1657 |
+
// Sometimes a length can't be determined at all (eg generators)
|
1658 |
+
// In which case simply return 0
|
1659 |
+
PyErr_Clear();
|
1660 |
+
return 0;
|
1661 |
+
}
|
1662 |
+
return (size_t) result;
|
1663 |
+
}
|
1664 |
+
|
1665 |
+
inline str repr(handle h) {
|
1666 |
+
PyObject *str_value = PyObject_Repr(h.ptr());
|
1667 |
+
if (!str_value) throw error_already_set();
|
1668 |
+
#if PY_MAJOR_VERSION < 3
|
1669 |
+
PyObject *unicode = PyUnicode_FromEncodedObject(str_value, "utf-8", nullptr);
|
1670 |
+
Py_XDECREF(str_value); str_value = unicode;
|
1671 |
+
if (!str_value) throw error_already_set();
|
1672 |
+
#endif
|
1673 |
+
return reinterpret_steal<str>(str_value);
|
1674 |
+
}
|
1675 |
+
|
1676 |
+
inline iterator iter(handle obj) {
|
1677 |
+
PyObject *result = PyObject_GetIter(obj.ptr());
|
1678 |
+
if (!result) { throw error_already_set(); }
|
1679 |
+
return reinterpret_steal<iterator>(result);
|
1680 |
+
}
|
1681 |
+
/// @} python_builtins
|
1682 |
+
|
1683 |
+
PYBIND11_NAMESPACE_BEGIN(detail)
|
1684 |
+
template <typename D> iterator object_api<D>::begin() const { return iter(derived()); }
|
1685 |
+
template <typename D> iterator object_api<D>::end() const { return iterator::sentinel(); }
|
1686 |
+
template <typename D> item_accessor object_api<D>::operator[](handle key) const {
|
1687 |
+
return {derived(), reinterpret_borrow<object>(key)};
|
1688 |
+
}
|
1689 |
+
template <typename D> item_accessor object_api<D>::operator[](const char *key) const {
|
1690 |
+
return {derived(), pybind11::str(key)};
|
1691 |
+
}
|
1692 |
+
template <typename D> obj_attr_accessor object_api<D>::attr(handle key) const {
|
1693 |
+
return {derived(), reinterpret_borrow<object>(key)};
|
1694 |
+
}
|
1695 |
+
template <typename D> str_attr_accessor object_api<D>::attr(const char *key) const {
|
1696 |
+
return {derived(), key};
|
1697 |
+
}
|
1698 |
+
template <typename D> args_proxy object_api<D>::operator*() const {
|
1699 |
+
return args_proxy(derived().ptr());
|
1700 |
+
}
|
1701 |
+
template <typename D> template <typename T> bool object_api<D>::contains(T &&item) const {
|
1702 |
+
return attr("__contains__")(std::forward<T>(item)).template cast<bool>();
|
1703 |
+
}
|
1704 |
+
|
1705 |
+
template <typename D>
|
1706 |
+
pybind11::str object_api<D>::str() const { return pybind11::str(derived()); }
|
1707 |
+
|
1708 |
+
template <typename D>
|
1709 |
+
str_attr_accessor object_api<D>::doc() const { return attr("__doc__"); }
|
1710 |
+
|
1711 |
+
template <typename D>
|
1712 |
+
handle object_api<D>::get_type() const { return type::handle_of(derived()); }
|
1713 |
+
|
1714 |
+
template <typename D>
|
1715 |
+
bool object_api<D>::rich_compare(object_api const &other, int value) const {
|
1716 |
+
int rv = PyObject_RichCompareBool(derived().ptr(), other.derived().ptr(), value);
|
1717 |
+
if (rv == -1)
|
1718 |
+
throw error_already_set();
|
1719 |
+
return rv == 1;
|
1720 |
+
}
|
1721 |
+
|
1722 |
+
#define PYBIND11_MATH_OPERATOR_UNARY(op, fn) \
|
1723 |
+
template <typename D> object object_api<D>::op() const { \
|
1724 |
+
object result = reinterpret_steal<object>(fn(derived().ptr())); \
|
1725 |
+
if (!result.ptr()) \
|
1726 |
+
throw error_already_set(); \
|
1727 |
+
return result; \
|
1728 |
+
}
|
1729 |
+
|
1730 |
+
#define PYBIND11_MATH_OPERATOR_BINARY(op, fn) \
|
1731 |
+
template <typename D> \
|
1732 |
+
object object_api<D>::op(object_api const &other) const { \
|
1733 |
+
object result = reinterpret_steal<object>( \
|
1734 |
+
fn(derived().ptr(), other.derived().ptr())); \
|
1735 |
+
if (!result.ptr()) \
|
1736 |
+
throw error_already_set(); \
|
1737 |
+
return result; \
|
1738 |
+
}
|
1739 |
+
|
1740 |
+
PYBIND11_MATH_OPERATOR_UNARY (operator~, PyNumber_Invert)
|
1741 |
+
PYBIND11_MATH_OPERATOR_UNARY (operator-, PyNumber_Negative)
|
1742 |
+
PYBIND11_MATH_OPERATOR_BINARY(operator+, PyNumber_Add)
|
1743 |
+
PYBIND11_MATH_OPERATOR_BINARY(operator+=, PyNumber_InPlaceAdd)
|
1744 |
+
PYBIND11_MATH_OPERATOR_BINARY(operator-, PyNumber_Subtract)
|
1745 |
+
PYBIND11_MATH_OPERATOR_BINARY(operator-=, PyNumber_InPlaceSubtract)
|
1746 |
+
PYBIND11_MATH_OPERATOR_BINARY(operator*, PyNumber_Multiply)
|
1747 |
+
PYBIND11_MATH_OPERATOR_BINARY(operator*=, PyNumber_InPlaceMultiply)
|
1748 |
+
PYBIND11_MATH_OPERATOR_BINARY(operator/, PyNumber_TrueDivide)
|
1749 |
+
PYBIND11_MATH_OPERATOR_BINARY(operator/=, PyNumber_InPlaceTrueDivide)
|
1750 |
+
PYBIND11_MATH_OPERATOR_BINARY(operator|, PyNumber_Or)
|
1751 |
+
PYBIND11_MATH_OPERATOR_BINARY(operator|=, PyNumber_InPlaceOr)
|
1752 |
+
PYBIND11_MATH_OPERATOR_BINARY(operator&, PyNumber_And)
|
1753 |
+
PYBIND11_MATH_OPERATOR_BINARY(operator&=, PyNumber_InPlaceAnd)
|
1754 |
+
PYBIND11_MATH_OPERATOR_BINARY(operator^, PyNumber_Xor)
|
1755 |
+
PYBIND11_MATH_OPERATOR_BINARY(operator^=, PyNumber_InPlaceXor)
|
1756 |
+
PYBIND11_MATH_OPERATOR_BINARY(operator<<, PyNumber_Lshift)
|
1757 |
+
PYBIND11_MATH_OPERATOR_BINARY(operator<<=, PyNumber_InPlaceLshift)
|
1758 |
+
PYBIND11_MATH_OPERATOR_BINARY(operator>>, PyNumber_Rshift)
|
1759 |
+
PYBIND11_MATH_OPERATOR_BINARY(operator>>=, PyNumber_InPlaceRshift)
|
1760 |
+
|
1761 |
+
#undef PYBIND11_MATH_OPERATOR_UNARY
|
1762 |
+
#undef PYBIND11_MATH_OPERATOR_BINARY
|
1763 |
+
|
1764 |
+
PYBIND11_NAMESPACE_END(detail)
|
1765 |
+
PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)
|
third-party/DPVO/Pangolin/components/pango_python/pybind11/include/pybind11/stl.h
ADDED
@@ -0,0 +1,396 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/*
|
2 |
+
pybind11/stl.h: Transparent conversion for STL data types
|
3 |
+
|
4 |
+
Copyright (c) 2016 Wenzel Jakob <[email protected]>
|
5 |
+
|
6 |
+
All rights reserved. Use of this source code is governed by a
|
7 |
+
BSD-style license that can be found in the LICENSE file.
|
8 |
+
*/
|
9 |
+
|
10 |
+
#pragma once
|
11 |
+
|
12 |
+
#include "pybind11.h"
|
13 |
+
#include <set>
|
14 |
+
#include <unordered_set>
|
15 |
+
#include <map>
|
16 |
+
#include <unordered_map>
|
17 |
+
#include <iostream>
|
18 |
+
#include <list>
|
19 |
+
#include <deque>
|
20 |
+
#include <valarray>
|
21 |
+
|
22 |
+
#if defined(_MSC_VER)
|
23 |
+
#pragma warning(push)
|
24 |
+
#pragma warning(disable: 4127) // warning C4127: Conditional expression is constant
|
25 |
+
#endif
|
26 |
+
|
27 |
+
#ifdef __has_include
|
28 |
+
// std::optional (but including it in c++14 mode isn't allowed)
|
29 |
+
# if defined(PYBIND11_CPP17) && __has_include(<optional>)
|
30 |
+
# include <optional>
|
31 |
+
# define PYBIND11_HAS_OPTIONAL 1
|
32 |
+
# endif
|
33 |
+
// std::experimental::optional (but not allowed in c++11 mode)
|
34 |
+
# if defined(PYBIND11_CPP14) && (__has_include(<experimental/optional>) && \
|
35 |
+
!__has_include(<optional>))
|
36 |
+
# include <experimental/optional>
|
37 |
+
# define PYBIND11_HAS_EXP_OPTIONAL 1
|
38 |
+
# endif
|
39 |
+
// std::variant
|
40 |
+
# if defined(PYBIND11_CPP17) && __has_include(<variant>)
|
41 |
+
# include <variant>
|
42 |
+
# define PYBIND11_HAS_VARIANT 1
|
43 |
+
# endif
|
44 |
+
#elif defined(_MSC_VER) && defined(PYBIND11_CPP17)
|
45 |
+
# include <optional>
|
46 |
+
# include <variant>
|
47 |
+
# define PYBIND11_HAS_OPTIONAL 1
|
48 |
+
# define PYBIND11_HAS_VARIANT 1
|
49 |
+
#endif
|
50 |
+
|
51 |
+
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
|
52 |
+
PYBIND11_NAMESPACE_BEGIN(detail)
|
53 |
+
|
54 |
+
/// Extracts an const lvalue reference or rvalue reference for U based on the type of T (e.g. for
|
55 |
+
/// forwarding a container element). Typically used indirect via forwarded_type(), below.
|
56 |
+
template <typename T, typename U>
|
57 |
+
using forwarded_type = conditional_t<
|
58 |
+
std::is_lvalue_reference<T>::value, remove_reference_t<U> &, remove_reference_t<U> &&>;
|
59 |
+
|
60 |
+
/// Forwards a value U as rvalue or lvalue according to whether T is rvalue or lvalue; typically
|
61 |
+
/// used for forwarding a container's elements.
|
62 |
+
template <typename T, typename U>
|
63 |
+
forwarded_type<T, U> forward_like(U &&u) {
|
64 |
+
return std::forward<detail::forwarded_type<T, U>>(std::forward<U>(u));
|
65 |
+
}
|
66 |
+
|
67 |
+
template <typename Type, typename Key> struct set_caster {
|
68 |
+
using type = Type;
|
69 |
+
using key_conv = make_caster<Key>;
|
70 |
+
|
71 |
+
bool load(handle src, bool convert) {
|
72 |
+
if (!isinstance<pybind11::set>(src))
|
73 |
+
return false;
|
74 |
+
auto s = reinterpret_borrow<pybind11::set>(src);
|
75 |
+
value.clear();
|
76 |
+
for (auto entry : s) {
|
77 |
+
key_conv conv;
|
78 |
+
if (!conv.load(entry, convert))
|
79 |
+
return false;
|
80 |
+
value.insert(cast_op<Key &&>(std::move(conv)));
|
81 |
+
}
|
82 |
+
return true;
|
83 |
+
}
|
84 |
+
|
85 |
+
template <typename T>
|
86 |
+
static handle cast(T &&src, return_value_policy policy, handle parent) {
|
87 |
+
if (!std::is_lvalue_reference<T>::value)
|
88 |
+
policy = return_value_policy_override<Key>::policy(policy);
|
89 |
+
pybind11::set s;
|
90 |
+
for (auto &&value : src) {
|
91 |
+
auto value_ = reinterpret_steal<object>(key_conv::cast(forward_like<T>(value), policy, parent));
|
92 |
+
if (!value_ || !s.add(value_))
|
93 |
+
return handle();
|
94 |
+
}
|
95 |
+
return s.release();
|
96 |
+
}
|
97 |
+
|
98 |
+
PYBIND11_TYPE_CASTER(type, _("Set[") + key_conv::name + _("]"));
|
99 |
+
};
|
100 |
+
|
101 |
+
template <typename Type, typename Key, typename Value> struct map_caster {
|
102 |
+
using key_conv = make_caster<Key>;
|
103 |
+
using value_conv = make_caster<Value>;
|
104 |
+
|
105 |
+
bool load(handle src, bool convert) {
|
106 |
+
if (!isinstance<dict>(src))
|
107 |
+
return false;
|
108 |
+
auto d = reinterpret_borrow<dict>(src);
|
109 |
+
value.clear();
|
110 |
+
for (auto it : d) {
|
111 |
+
key_conv kconv;
|
112 |
+
value_conv vconv;
|
113 |
+
if (!kconv.load(it.first.ptr(), convert) ||
|
114 |
+
!vconv.load(it.second.ptr(), convert))
|
115 |
+
return false;
|
116 |
+
value.emplace(cast_op<Key &&>(std::move(kconv)), cast_op<Value &&>(std::move(vconv)));
|
117 |
+
}
|
118 |
+
return true;
|
119 |
+
}
|
120 |
+
|
121 |
+
template <typename T>
|
122 |
+
static handle cast(T &&src, return_value_policy policy, handle parent) {
|
123 |
+
dict d;
|
124 |
+
return_value_policy policy_key = policy;
|
125 |
+
return_value_policy policy_value = policy;
|
126 |
+
if (!std::is_lvalue_reference<T>::value) {
|
127 |
+
policy_key = return_value_policy_override<Key>::policy(policy_key);
|
128 |
+
policy_value = return_value_policy_override<Value>::policy(policy_value);
|
129 |
+
}
|
130 |
+
for (auto &&kv : src) {
|
131 |
+
auto key = reinterpret_steal<object>(key_conv::cast(forward_like<T>(kv.first), policy_key, parent));
|
132 |
+
auto value = reinterpret_steal<object>(value_conv::cast(forward_like<T>(kv.second), policy_value, parent));
|
133 |
+
if (!key || !value)
|
134 |
+
return handle();
|
135 |
+
d[key] = value;
|
136 |
+
}
|
137 |
+
return d.release();
|
138 |
+
}
|
139 |
+
|
140 |
+
PYBIND11_TYPE_CASTER(Type, _("Dict[") + key_conv::name + _(", ") + value_conv::name + _("]"));
|
141 |
+
};
|
142 |
+
|
143 |
+
template <typename Type, typename Value> struct list_caster {
|
144 |
+
using value_conv = make_caster<Value>;
|
145 |
+
|
146 |
+
bool load(handle src, bool convert) {
|
147 |
+
if (!isinstance<sequence>(src) || isinstance<bytes>(src) || isinstance<str>(src))
|
148 |
+
return false;
|
149 |
+
auto s = reinterpret_borrow<sequence>(src);
|
150 |
+
value.clear();
|
151 |
+
reserve_maybe(s, &value);
|
152 |
+
for (auto it : s) {
|
153 |
+
value_conv conv;
|
154 |
+
if (!conv.load(it, convert))
|
155 |
+
return false;
|
156 |
+
value.push_back(cast_op<Value &&>(std::move(conv)));
|
157 |
+
}
|
158 |
+
return true;
|
159 |
+
}
|
160 |
+
|
161 |
+
private:
|
162 |
+
template <
|
163 |
+
typename T = Type,
|
164 |
+
enable_if_t<std::is_same<decltype(std::declval<T>().reserve(0)), void>::value, int> = 0>
|
165 |
+
void reserve_maybe(const sequence &s, Type *) {
|
166 |
+
value.reserve(s.size());
|
167 |
+
}
|
168 |
+
void reserve_maybe(const sequence &, void *) {}
|
169 |
+
|
170 |
+
public:
|
171 |
+
template <typename T>
|
172 |
+
static handle cast(T &&src, return_value_policy policy, handle parent) {
|
173 |
+
if (!std::is_lvalue_reference<T>::value)
|
174 |
+
policy = return_value_policy_override<Value>::policy(policy);
|
175 |
+
list l(src.size());
|
176 |
+
size_t index = 0;
|
177 |
+
for (auto &&value : src) {
|
178 |
+
auto value_ = reinterpret_steal<object>(value_conv::cast(forward_like<T>(value), policy, parent));
|
179 |
+
if (!value_)
|
180 |
+
return handle();
|
181 |
+
PyList_SET_ITEM(l.ptr(), (ssize_t) index++, value_.release().ptr()); // steals a reference
|
182 |
+
}
|
183 |
+
return l.release();
|
184 |
+
}
|
185 |
+
|
186 |
+
PYBIND11_TYPE_CASTER(Type, _("List[") + value_conv::name + _("]"));
|
187 |
+
};
|
188 |
+
|
189 |
+
template <typename Type, typename Alloc> struct type_caster<std::vector<Type, Alloc>>
|
190 |
+
: list_caster<std::vector<Type, Alloc>, Type> { };
|
191 |
+
|
192 |
+
template <typename Type, typename Alloc> struct type_caster<std::deque<Type, Alloc>>
|
193 |
+
: list_caster<std::deque<Type, Alloc>, Type> { };
|
194 |
+
|
195 |
+
template <typename Type, typename Alloc> struct type_caster<std::list<Type, Alloc>>
|
196 |
+
: list_caster<std::list<Type, Alloc>, Type> { };
|
197 |
+
|
198 |
+
template <typename ArrayType, typename Value, bool Resizable, size_t Size = 0> struct array_caster {
|
199 |
+
using value_conv = make_caster<Value>;
|
200 |
+
|
201 |
+
private:
|
202 |
+
template <bool R = Resizable>
|
203 |
+
bool require_size(enable_if_t<R, size_t> size) {
|
204 |
+
if (value.size() != size)
|
205 |
+
value.resize(size);
|
206 |
+
return true;
|
207 |
+
}
|
208 |
+
template <bool R = Resizable>
|
209 |
+
bool require_size(enable_if_t<!R, size_t> size) {
|
210 |
+
return size == Size;
|
211 |
+
}
|
212 |
+
|
213 |
+
public:
|
214 |
+
bool load(handle src, bool convert) {
|
215 |
+
if (!isinstance<sequence>(src))
|
216 |
+
return false;
|
217 |
+
auto l = reinterpret_borrow<sequence>(src);
|
218 |
+
if (!require_size(l.size()))
|
219 |
+
return false;
|
220 |
+
size_t ctr = 0;
|
221 |
+
for (auto it : l) {
|
222 |
+
value_conv conv;
|
223 |
+
if (!conv.load(it, convert))
|
224 |
+
return false;
|
225 |
+
value[ctr++] = cast_op<Value &&>(std::move(conv));
|
226 |
+
}
|
227 |
+
return true;
|
228 |
+
}
|
229 |
+
|
230 |
+
template <typename T>
|
231 |
+
static handle cast(T &&src, return_value_policy policy, handle parent) {
|
232 |
+
list l(src.size());
|
233 |
+
size_t index = 0;
|
234 |
+
for (auto &&value : src) {
|
235 |
+
auto value_ = reinterpret_steal<object>(value_conv::cast(forward_like<T>(value), policy, parent));
|
236 |
+
if (!value_)
|
237 |
+
return handle();
|
238 |
+
PyList_SET_ITEM(l.ptr(), (ssize_t) index++, value_.release().ptr()); // steals a reference
|
239 |
+
}
|
240 |
+
return l.release();
|
241 |
+
}
|
242 |
+
|
243 |
+
PYBIND11_TYPE_CASTER(ArrayType, _("List[") + value_conv::name + _<Resizable>(_(""), _("[") + _<Size>() + _("]")) + _("]"));
|
244 |
+
};
|
245 |
+
|
246 |
+
template <typename Type, size_t Size> struct type_caster<std::array<Type, Size>>
|
247 |
+
: array_caster<std::array<Type, Size>, Type, false, Size> { };
|
248 |
+
|
249 |
+
template <typename Type> struct type_caster<std::valarray<Type>>
|
250 |
+
: array_caster<std::valarray<Type>, Type, true> { };
|
251 |
+
|
252 |
+
template <typename Key, typename Compare, typename Alloc> struct type_caster<std::set<Key, Compare, Alloc>>
|
253 |
+
: set_caster<std::set<Key, Compare, Alloc>, Key> { };
|
254 |
+
|
255 |
+
template <typename Key, typename Hash, typename Equal, typename Alloc> struct type_caster<std::unordered_set<Key, Hash, Equal, Alloc>>
|
256 |
+
: set_caster<std::unordered_set<Key, Hash, Equal, Alloc>, Key> { };
|
257 |
+
|
258 |
+
template <typename Key, typename Value, typename Compare, typename Alloc> struct type_caster<std::map<Key, Value, Compare, Alloc>>
|
259 |
+
: map_caster<std::map<Key, Value, Compare, Alloc>, Key, Value> { };
|
260 |
+
|
261 |
+
template <typename Key, typename Value, typename Hash, typename Equal, typename Alloc> struct type_caster<std::unordered_map<Key, Value, Hash, Equal, Alloc>>
|
262 |
+
: map_caster<std::unordered_map<Key, Value, Hash, Equal, Alloc>, Key, Value> { };
|
263 |
+
|
264 |
+
// This type caster is intended to be used for std::optional and std::experimental::optional
|
265 |
+
template<typename T> struct optional_caster {
|
266 |
+
using value_conv = make_caster<typename T::value_type>;
|
267 |
+
|
268 |
+
template <typename T_>
|
269 |
+
static handle cast(T_ &&src, return_value_policy policy, handle parent) {
|
270 |
+
if (!src)
|
271 |
+
return none().inc_ref();
|
272 |
+
if (!std::is_lvalue_reference<T>::value) {
|
273 |
+
policy = return_value_policy_override<T>::policy(policy);
|
274 |
+
}
|
275 |
+
return value_conv::cast(*std::forward<T_>(src), policy, parent);
|
276 |
+
}
|
277 |
+
|
278 |
+
bool load(handle src, bool convert) {
|
279 |
+
if (!src) {
|
280 |
+
return false;
|
281 |
+
}
|
282 |
+
if (src.is_none()) {
|
283 |
+
return true; // default-constructed value is already empty
|
284 |
+
}
|
285 |
+
value_conv inner_caster;
|
286 |
+
if (!inner_caster.load(src, convert))
|
287 |
+
return false;
|
288 |
+
|
289 |
+
value.emplace(cast_op<typename T::value_type &&>(std::move(inner_caster)));
|
290 |
+
return true;
|
291 |
+
}
|
292 |
+
|
293 |
+
PYBIND11_TYPE_CASTER(T, _("Optional[") + value_conv::name + _("]"));
|
294 |
+
};
|
295 |
+
|
296 |
+
#if defined(PYBIND11_HAS_OPTIONAL)
|
297 |
+
template<typename T> struct type_caster<std::optional<T>>
|
298 |
+
: public optional_caster<std::optional<T>> {};
|
299 |
+
|
300 |
+
template<> struct type_caster<std::nullopt_t>
|
301 |
+
: public void_caster<std::nullopt_t> {};
|
302 |
+
#endif
|
303 |
+
|
304 |
+
#if defined(PYBIND11_HAS_EXP_OPTIONAL)
|
305 |
+
template<typename T> struct type_caster<std::experimental::optional<T>>
|
306 |
+
: public optional_caster<std::experimental::optional<T>> {};
|
307 |
+
|
308 |
+
template<> struct type_caster<std::experimental::nullopt_t>
|
309 |
+
: public void_caster<std::experimental::nullopt_t> {};
|
310 |
+
#endif
|
311 |
+
|
312 |
+
/// Visit a variant and cast any found type to Python
|
313 |
+
struct variant_caster_visitor {
|
314 |
+
return_value_policy policy;
|
315 |
+
handle parent;
|
316 |
+
|
317 |
+
using result_type = handle; // required by boost::variant in C++11
|
318 |
+
|
319 |
+
template <typename T>
|
320 |
+
result_type operator()(T &&src) const {
|
321 |
+
return make_caster<T>::cast(std::forward<T>(src), policy, parent);
|
322 |
+
}
|
323 |
+
};
|
324 |
+
|
325 |
+
/// Helper class which abstracts away variant's `visit` function. `std::variant` and similar
|
326 |
+
/// `namespace::variant` types which provide a `namespace::visit()` function are handled here
|
327 |
+
/// automatically using argument-dependent lookup. Users can provide specializations for other
|
328 |
+
/// variant-like classes, e.g. `boost::variant` and `boost::apply_visitor`.
|
329 |
+
template <template<typename...> class Variant>
|
330 |
+
struct visit_helper {
|
331 |
+
template <typename... Args>
|
332 |
+
static auto call(Args &&...args) -> decltype(visit(std::forward<Args>(args)...)) {
|
333 |
+
return visit(std::forward<Args>(args)...);
|
334 |
+
}
|
335 |
+
};
|
336 |
+
|
337 |
+
/// Generic variant caster
|
338 |
+
template <typename Variant> struct variant_caster;
|
339 |
+
|
340 |
+
template <template<typename...> class V, typename... Ts>
|
341 |
+
struct variant_caster<V<Ts...>> {
|
342 |
+
static_assert(sizeof...(Ts) > 0, "Variant must consist of at least one alternative.");
|
343 |
+
|
344 |
+
template <typename U, typename... Us>
|
345 |
+
bool load_alternative(handle src, bool convert, type_list<U, Us...>) {
|
346 |
+
auto caster = make_caster<U>();
|
347 |
+
if (caster.load(src, convert)) {
|
348 |
+
value = cast_op<U>(caster);
|
349 |
+
return true;
|
350 |
+
}
|
351 |
+
return load_alternative(src, convert, type_list<Us...>{});
|
352 |
+
}
|
353 |
+
|
354 |
+
bool load_alternative(handle, bool, type_list<>) { return false; }
|
355 |
+
|
356 |
+
bool load(handle src, bool convert) {
|
357 |
+
// Do a first pass without conversions to improve constructor resolution.
|
358 |
+
// E.g. `py::int_(1).cast<variant<double, int>>()` needs to fill the `int`
|
359 |
+
// slot of the variant. Without two-pass loading `double` would be filled
|
360 |
+
// because it appears first and a conversion is possible.
|
361 |
+
if (convert && load_alternative(src, false, type_list<Ts...>{}))
|
362 |
+
return true;
|
363 |
+
return load_alternative(src, convert, type_list<Ts...>{});
|
364 |
+
}
|
365 |
+
|
366 |
+
template <typename Variant>
|
367 |
+
static handle cast(Variant &&src, return_value_policy policy, handle parent) {
|
368 |
+
return visit_helper<V>::call(variant_caster_visitor{policy, parent},
|
369 |
+
std::forward<Variant>(src));
|
370 |
+
}
|
371 |
+
|
372 |
+
using Type = V<Ts...>;
|
373 |
+
PYBIND11_TYPE_CASTER(Type, _("Union[") + detail::concat(make_caster<Ts>::name...) + _("]"));
|
374 |
+
};
|
375 |
+
|
376 |
+
#if defined(PYBIND11_HAS_VARIANT)
|
377 |
+
template <typename... Ts>
|
378 |
+
struct type_caster<std::variant<Ts...>> : variant_caster<std::variant<Ts...>> { };
|
379 |
+
#endif
|
380 |
+
|
381 |
+
PYBIND11_NAMESPACE_END(detail)
|
382 |
+
|
383 |
+
inline std::ostream &operator<<(std::ostream &os, const handle &obj) {
|
384 |
+
#ifdef PYBIND11_HAS_STRING_VIEW
|
385 |
+
os << str(obj).cast<std::string_view>();
|
386 |
+
#else
|
387 |
+
os << (std::string) str(obj);
|
388 |
+
#endif
|
389 |
+
return os;
|
390 |
+
}
|
391 |
+
|
392 |
+
PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)
|
393 |
+
|
394 |
+
#if defined(_MSC_VER)
|
395 |
+
#pragma warning(pop)
|
396 |
+
#endif
|
third-party/DPVO/Pangolin/components/pango_python/pybind11/include/pybind11/stl/filesystem.h
ADDED
@@ -0,0 +1,103 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
// Copyright (c) 2021 The Pybind Development Team.
|
2 |
+
// All rights reserved. Use of this source code is governed by a
|
3 |
+
// BSD-style license that can be found in the LICENSE file.
|
4 |
+
|
5 |
+
#pragma once
|
6 |
+
|
7 |
+
#include "../cast.h"
|
8 |
+
#include "../pybind11.h"
|
9 |
+
#include "../pytypes.h"
|
10 |
+
|
11 |
+
#include "../detail/common.h"
|
12 |
+
#include "../detail/descr.h"
|
13 |
+
|
14 |
+
#include <string>
|
15 |
+
|
16 |
+
#ifdef __has_include
|
17 |
+
# if defined(PYBIND11_CPP17) && __has_include(<filesystem>) && \
|
18 |
+
PY_VERSION_HEX >= 0x03060000
|
19 |
+
# include <filesystem>
|
20 |
+
# define PYBIND11_HAS_FILESYSTEM 1
|
21 |
+
# endif
|
22 |
+
#endif
|
23 |
+
|
24 |
+
#if !defined(PYBIND11_HAS_FILESYSTEM) && !defined(PYBIND11_HAS_FILESYSTEM_IS_OPTIONAL)
|
25 |
+
# error \
|
26 |
+
"#include <filesystem> is not available. (Use -DPYBIND11_HAS_FILESYSTEM_IS_OPTIONAL to ignore.)"
|
27 |
+
#endif
|
28 |
+
|
29 |
+
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
|
30 |
+
PYBIND11_NAMESPACE_BEGIN(detail)
|
31 |
+
|
32 |
+
#if defined(PYBIND11_HAS_FILESYSTEM)
|
33 |
+
template<typename T> struct path_caster {
|
34 |
+
|
35 |
+
private:
|
36 |
+
static PyObject* unicode_from_fs_native(const std::string& w) {
|
37 |
+
#if !defined(PYPY_VERSION)
|
38 |
+
return PyUnicode_DecodeFSDefaultAndSize(w.c_str(), ssize_t(w.size()));
|
39 |
+
#else
|
40 |
+
// PyPy mistakenly declares the first parameter as non-const.
|
41 |
+
return PyUnicode_DecodeFSDefaultAndSize(
|
42 |
+
const_cast<char*>(w.c_str()), ssize_t(w.size()));
|
43 |
+
#endif
|
44 |
+
}
|
45 |
+
|
46 |
+
static PyObject* unicode_from_fs_native(const std::wstring& w) {
|
47 |
+
return PyUnicode_FromWideChar(w.c_str(), ssize_t(w.size()));
|
48 |
+
}
|
49 |
+
|
50 |
+
public:
|
51 |
+
static handle cast(const T& path, return_value_policy, handle) {
|
52 |
+
if (auto py_str = unicode_from_fs_native(path.native())) {
|
53 |
+
return module_::import("pathlib").attr("Path")(reinterpret_steal<object>(py_str))
|
54 |
+
.release();
|
55 |
+
}
|
56 |
+
return nullptr;
|
57 |
+
}
|
58 |
+
|
59 |
+
bool load(handle handle, bool) {
|
60 |
+
// PyUnicode_FSConverter and PyUnicode_FSDecoder normally take care of
|
61 |
+
// calling PyOS_FSPath themselves, but that's broken on PyPy (PyPy
|
62 |
+
// issue #3168) so we do it ourselves instead.
|
63 |
+
PyObject* buf = PyOS_FSPath(handle.ptr());
|
64 |
+
if (!buf) {
|
65 |
+
PyErr_Clear();
|
66 |
+
return false;
|
67 |
+
}
|
68 |
+
PyObject* native = nullptr;
|
69 |
+
if constexpr (std::is_same_v<typename T::value_type, char>) {
|
70 |
+
if (PyUnicode_FSConverter(buf, &native) != 0) {
|
71 |
+
if (auto c_str = PyBytes_AsString(native)) {
|
72 |
+
// AsString returns a pointer to the internal buffer, which
|
73 |
+
// must not be free'd.
|
74 |
+
value = c_str;
|
75 |
+
}
|
76 |
+
}
|
77 |
+
} else if constexpr (std::is_same_v<typename T::value_type, wchar_t>) {
|
78 |
+
if (PyUnicode_FSDecoder(buf, &native) != 0) {
|
79 |
+
if (auto c_str = PyUnicode_AsWideCharString(native, nullptr)) {
|
80 |
+
// AsWideCharString returns a new string that must be free'd.
|
81 |
+
value = c_str; // Copies the string.
|
82 |
+
PyMem_Free(c_str);
|
83 |
+
}
|
84 |
+
}
|
85 |
+
}
|
86 |
+
Py_XDECREF(native);
|
87 |
+
Py_DECREF(buf);
|
88 |
+
if (PyErr_Occurred()) {
|
89 |
+
PyErr_Clear();
|
90 |
+
return false;
|
91 |
+
}
|
92 |
+
return true;
|
93 |
+
}
|
94 |
+
|
95 |
+
PYBIND11_TYPE_CASTER(T, _("os.PathLike"));
|
96 |
+
};
|
97 |
+
|
98 |
+
template<> struct type_caster<std::filesystem::path>
|
99 |
+
: public path_caster<std::filesystem::path> {};
|
100 |
+
#endif // PYBIND11_HAS_FILESYSTEM
|
101 |
+
|
102 |
+
PYBIND11_NAMESPACE_END(detail)
|
103 |
+
PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)
|
third-party/DPVO/Pangolin/components/pango_python/pybind11/include/pybind11/stl_bind.h
ADDED
@@ -0,0 +1,675 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/*
|
2 |
+
pybind11/std_bind.h: Binding generators for STL data types
|
3 |
+
|
4 |
+
Copyright (c) 2016 Sergey Lyskov and Wenzel Jakob
|
5 |
+
|
6 |
+
All rights reserved. Use of this source code is governed by a
|
7 |
+
BSD-style license that can be found in the LICENSE file.
|
8 |
+
*/
|
9 |
+
|
10 |
+
#pragma once
|
11 |
+
|
12 |
+
#include "detail/common.h"
|
13 |
+
#include "operators.h"
|
14 |
+
|
15 |
+
#include <algorithm>
|
16 |
+
#include <sstream>
|
17 |
+
|
18 |
+
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
|
19 |
+
PYBIND11_NAMESPACE_BEGIN(detail)
|
20 |
+
|
21 |
+
/* SFINAE helper class used by 'is_comparable */
|
22 |
+
template <typename T> struct container_traits {
|
23 |
+
template <typename T2> static std::true_type test_comparable(decltype(std::declval<const T2 &>() == std::declval<const T2 &>())*);
|
24 |
+
template <typename T2> static std::false_type test_comparable(...);
|
25 |
+
template <typename T2> static std::true_type test_value(typename T2::value_type *);
|
26 |
+
template <typename T2> static std::false_type test_value(...);
|
27 |
+
template <typename T2> static std::true_type test_pair(typename T2::first_type *, typename T2::second_type *);
|
28 |
+
template <typename T2> static std::false_type test_pair(...);
|
29 |
+
|
30 |
+
static constexpr const bool is_comparable = std::is_same<std::true_type, decltype(test_comparable<T>(nullptr))>::value;
|
31 |
+
static constexpr const bool is_pair = std::is_same<std::true_type, decltype(test_pair<T>(nullptr, nullptr))>::value;
|
32 |
+
static constexpr const bool is_vector = std::is_same<std::true_type, decltype(test_value<T>(nullptr))>::value;
|
33 |
+
static constexpr const bool is_element = !is_pair && !is_vector;
|
34 |
+
};
|
35 |
+
|
36 |
+
/* Default: is_comparable -> std::false_type */
|
37 |
+
template <typename T, typename SFINAE = void>
|
38 |
+
struct is_comparable : std::false_type { };
|
39 |
+
|
40 |
+
/* For non-map data structures, check whether operator== can be instantiated */
|
41 |
+
template <typename T>
|
42 |
+
struct is_comparable<
|
43 |
+
T, enable_if_t<container_traits<T>::is_element &&
|
44 |
+
container_traits<T>::is_comparable>>
|
45 |
+
: std::true_type { };
|
46 |
+
|
47 |
+
/* For a vector/map data structure, recursively check the value type (which is std::pair for maps) */
|
48 |
+
template <typename T>
|
49 |
+
struct is_comparable<T, enable_if_t<container_traits<T>::is_vector>> {
|
50 |
+
static constexpr const bool value =
|
51 |
+
is_comparable<typename T::value_type>::value;
|
52 |
+
};
|
53 |
+
|
54 |
+
/* For pairs, recursively check the two data types */
|
55 |
+
template <typename T>
|
56 |
+
struct is_comparable<T, enable_if_t<container_traits<T>::is_pair>> {
|
57 |
+
static constexpr const bool value =
|
58 |
+
is_comparable<typename T::first_type>::value &&
|
59 |
+
is_comparable<typename T::second_type>::value;
|
60 |
+
};
|
61 |
+
|
62 |
+
/* Fallback functions */
|
63 |
+
template <typename, typename, typename... Args> void vector_if_copy_constructible(const Args &...) { }
|
64 |
+
template <typename, typename, typename... Args> void vector_if_equal_operator(const Args &...) { }
|
65 |
+
template <typename, typename, typename... Args> void vector_if_insertion_operator(const Args &...) { }
|
66 |
+
template <typename, typename, typename... Args> void vector_modifiers(const Args &...) { }
|
67 |
+
|
68 |
+
template<typename Vector, typename Class_>
|
69 |
+
void vector_if_copy_constructible(enable_if_t<is_copy_constructible<Vector>::value, Class_> &cl) {
|
70 |
+
cl.def(init<const Vector &>(), "Copy constructor");
|
71 |
+
}
|
72 |
+
|
73 |
+
template<typename Vector, typename Class_>
|
74 |
+
void vector_if_equal_operator(enable_if_t<is_comparable<Vector>::value, Class_> &cl) {
|
75 |
+
using T = typename Vector::value_type;
|
76 |
+
|
77 |
+
cl.def(self == self);
|
78 |
+
cl.def(self != self);
|
79 |
+
|
80 |
+
cl.def("count",
|
81 |
+
[](const Vector &v, const T &x) {
|
82 |
+
return std::count(v.begin(), v.end(), x);
|
83 |
+
},
|
84 |
+
arg("x"),
|
85 |
+
"Return the number of times ``x`` appears in the list"
|
86 |
+
);
|
87 |
+
|
88 |
+
cl.def("remove", [](Vector &v, const T &x) {
|
89 |
+
auto p = std::find(v.begin(), v.end(), x);
|
90 |
+
if (p != v.end())
|
91 |
+
v.erase(p);
|
92 |
+
else
|
93 |
+
throw value_error();
|
94 |
+
},
|
95 |
+
arg("x"),
|
96 |
+
"Remove the first item from the list whose value is x. "
|
97 |
+
"It is an error if there is no such item."
|
98 |
+
);
|
99 |
+
|
100 |
+
cl.def("__contains__",
|
101 |
+
[](const Vector &v, const T &x) {
|
102 |
+
return std::find(v.begin(), v.end(), x) != v.end();
|
103 |
+
},
|
104 |
+
arg("x"),
|
105 |
+
"Return true the container contains ``x``"
|
106 |
+
);
|
107 |
+
}
|
108 |
+
|
109 |
+
// Vector modifiers -- requires a copyable vector_type:
|
110 |
+
// (Technically, some of these (pop and __delitem__) don't actually require copyability, but it seems
|
111 |
+
// silly to allow deletion but not insertion, so include them here too.)
|
112 |
+
template <typename Vector, typename Class_>
|
113 |
+
void vector_modifiers(enable_if_t<is_copy_constructible<typename Vector::value_type>::value, Class_> &cl) {
|
114 |
+
using T = typename Vector::value_type;
|
115 |
+
using SizeType = typename Vector::size_type;
|
116 |
+
using DiffType = typename Vector::difference_type;
|
117 |
+
|
118 |
+
auto wrap_i = [](DiffType i, SizeType n) {
|
119 |
+
if (i < 0)
|
120 |
+
i += n;
|
121 |
+
if (i < 0 || (SizeType)i >= n)
|
122 |
+
throw index_error();
|
123 |
+
return i;
|
124 |
+
};
|
125 |
+
|
126 |
+
cl.def("append",
|
127 |
+
[](Vector &v, const T &value) { v.push_back(value); },
|
128 |
+
arg("x"),
|
129 |
+
"Add an item to the end of the list");
|
130 |
+
|
131 |
+
cl.def(init([](const iterable &it) {
|
132 |
+
auto v = std::unique_ptr<Vector>(new Vector());
|
133 |
+
v->reserve(len_hint(it));
|
134 |
+
for (handle h : it)
|
135 |
+
v->push_back(h.cast<T>());
|
136 |
+
return v.release();
|
137 |
+
}));
|
138 |
+
|
139 |
+
cl.def("clear",
|
140 |
+
[](Vector &v) {
|
141 |
+
v.clear();
|
142 |
+
},
|
143 |
+
"Clear the contents"
|
144 |
+
);
|
145 |
+
|
146 |
+
cl.def("extend",
|
147 |
+
[](Vector &v, const Vector &src) {
|
148 |
+
v.insert(v.end(), src.begin(), src.end());
|
149 |
+
},
|
150 |
+
arg("L"),
|
151 |
+
"Extend the list by appending all the items in the given list"
|
152 |
+
);
|
153 |
+
|
154 |
+
cl.def(
|
155 |
+
"extend",
|
156 |
+
[](Vector &v, const iterable &it) {
|
157 |
+
const size_t old_size = v.size();
|
158 |
+
v.reserve(old_size + len_hint(it));
|
159 |
+
try {
|
160 |
+
for (handle h : it) {
|
161 |
+
v.push_back(h.cast<T>());
|
162 |
+
}
|
163 |
+
} catch (const cast_error &) {
|
164 |
+
v.erase(v.begin() + static_cast<typename Vector::difference_type>(old_size),
|
165 |
+
v.end());
|
166 |
+
try {
|
167 |
+
v.shrink_to_fit();
|
168 |
+
} catch (const std::exception &) {
|
169 |
+
// Do nothing
|
170 |
+
}
|
171 |
+
throw;
|
172 |
+
}
|
173 |
+
},
|
174 |
+
arg("L"),
|
175 |
+
"Extend the list by appending all the items in the given list");
|
176 |
+
|
177 |
+
cl.def("insert",
|
178 |
+
[](Vector &v, DiffType i, const T &x) {
|
179 |
+
// Can't use wrap_i; i == v.size() is OK
|
180 |
+
if (i < 0)
|
181 |
+
i += v.size();
|
182 |
+
if (i < 0 || (SizeType)i > v.size())
|
183 |
+
throw index_error();
|
184 |
+
v.insert(v.begin() + i, x);
|
185 |
+
},
|
186 |
+
arg("i") , arg("x"),
|
187 |
+
"Insert an item at a given position."
|
188 |
+
);
|
189 |
+
|
190 |
+
cl.def("pop",
|
191 |
+
[](Vector &v) {
|
192 |
+
if (v.empty())
|
193 |
+
throw index_error();
|
194 |
+
T t = std::move(v.back());
|
195 |
+
v.pop_back();
|
196 |
+
return t;
|
197 |
+
},
|
198 |
+
"Remove and return the last item"
|
199 |
+
);
|
200 |
+
|
201 |
+
cl.def("pop",
|
202 |
+
[wrap_i](Vector &v, DiffType i) {
|
203 |
+
i = wrap_i(i, v.size());
|
204 |
+
T t = std::move(v[(SizeType) i]);
|
205 |
+
v.erase(std::next(v.begin(), i));
|
206 |
+
return t;
|
207 |
+
},
|
208 |
+
arg("i"),
|
209 |
+
"Remove and return the item at index ``i``"
|
210 |
+
);
|
211 |
+
|
212 |
+
cl.def("__setitem__",
|
213 |
+
[wrap_i](Vector &v, DiffType i, const T &t) {
|
214 |
+
i = wrap_i(i, v.size());
|
215 |
+
v[(SizeType)i] = t;
|
216 |
+
}
|
217 |
+
);
|
218 |
+
|
219 |
+
/// Slicing protocol
|
220 |
+
cl.def(
|
221 |
+
"__getitem__",
|
222 |
+
[](const Vector &v, slice slice) -> Vector * {
|
223 |
+
size_t start = 0, stop = 0, step = 0, slicelength = 0;
|
224 |
+
|
225 |
+
if (!slice.compute(v.size(), &start, &stop, &step, &slicelength))
|
226 |
+
throw error_already_set();
|
227 |
+
|
228 |
+
auto *seq = new Vector();
|
229 |
+
seq->reserve((size_t) slicelength);
|
230 |
+
|
231 |
+
for (size_t i=0; i<slicelength; ++i) {
|
232 |
+
seq->push_back(v[start]);
|
233 |
+
start += step;
|
234 |
+
}
|
235 |
+
return seq;
|
236 |
+
},
|
237 |
+
arg("s"),
|
238 |
+
"Retrieve list elements using a slice object");
|
239 |
+
|
240 |
+
cl.def(
|
241 |
+
"__setitem__",
|
242 |
+
[](Vector &v, slice slice, const Vector &value) {
|
243 |
+
size_t start = 0, stop = 0, step = 0, slicelength = 0;
|
244 |
+
if (!slice.compute(v.size(), &start, &stop, &step, &slicelength))
|
245 |
+
throw error_already_set();
|
246 |
+
|
247 |
+
if (slicelength != value.size())
|
248 |
+
throw std::runtime_error("Left and right hand size of slice assignment have different sizes!");
|
249 |
+
|
250 |
+
for (size_t i=0; i<slicelength; ++i) {
|
251 |
+
v[start] = value[i];
|
252 |
+
start += step;
|
253 |
+
}
|
254 |
+
},
|
255 |
+
"Assign list elements using a slice object");
|
256 |
+
|
257 |
+
cl.def("__delitem__",
|
258 |
+
[wrap_i](Vector &v, DiffType i) {
|
259 |
+
i = wrap_i(i, v.size());
|
260 |
+
v.erase(v.begin() + i);
|
261 |
+
},
|
262 |
+
"Delete the list elements at index ``i``"
|
263 |
+
);
|
264 |
+
|
265 |
+
cl.def(
|
266 |
+
"__delitem__",
|
267 |
+
[](Vector &v, slice slice) {
|
268 |
+
size_t start = 0, stop = 0, step = 0, slicelength = 0;
|
269 |
+
|
270 |
+
if (!slice.compute(v.size(), &start, &stop, &step, &slicelength))
|
271 |
+
throw error_already_set();
|
272 |
+
|
273 |
+
if (step == 1 && false) {
|
274 |
+
v.erase(v.begin() + (DiffType) start, v.begin() + DiffType(start + slicelength));
|
275 |
+
} else {
|
276 |
+
for (size_t i = 0; i < slicelength; ++i) {
|
277 |
+
v.erase(v.begin() + DiffType(start));
|
278 |
+
start += step - 1;
|
279 |
+
}
|
280 |
+
}
|
281 |
+
},
|
282 |
+
"Delete list elements using a slice object");
|
283 |
+
}
|
284 |
+
|
285 |
+
// If the type has an operator[] that doesn't return a reference (most notably std::vector<bool>),
|
286 |
+
// we have to access by copying; otherwise we return by reference.
|
287 |
+
template <typename Vector> using vector_needs_copy = negation<
|
288 |
+
std::is_same<decltype(std::declval<Vector>()[typename Vector::size_type()]), typename Vector::value_type &>>;
|
289 |
+
|
290 |
+
// The usual case: access and iterate by reference
|
291 |
+
template <typename Vector, typename Class_>
|
292 |
+
void vector_accessor(enable_if_t<!vector_needs_copy<Vector>::value, Class_> &cl) {
|
293 |
+
using T = typename Vector::value_type;
|
294 |
+
using SizeType = typename Vector::size_type;
|
295 |
+
using DiffType = typename Vector::difference_type;
|
296 |
+
using ItType = typename Vector::iterator;
|
297 |
+
|
298 |
+
auto wrap_i = [](DiffType i, SizeType n) {
|
299 |
+
if (i < 0)
|
300 |
+
i += n;
|
301 |
+
if (i < 0 || (SizeType)i >= n)
|
302 |
+
throw index_error();
|
303 |
+
return i;
|
304 |
+
};
|
305 |
+
|
306 |
+
cl.def("__getitem__",
|
307 |
+
[wrap_i](Vector &v, DiffType i) -> T & {
|
308 |
+
i = wrap_i(i, v.size());
|
309 |
+
return v[(SizeType)i];
|
310 |
+
},
|
311 |
+
return_value_policy::reference_internal // ref + keepalive
|
312 |
+
);
|
313 |
+
|
314 |
+
cl.def("__iter__",
|
315 |
+
[](Vector &v) {
|
316 |
+
return make_iterator<
|
317 |
+
return_value_policy::reference_internal, ItType, ItType, T&>(
|
318 |
+
v.begin(), v.end());
|
319 |
+
},
|
320 |
+
keep_alive<0, 1>() /* Essential: keep list alive while iterator exists */
|
321 |
+
);
|
322 |
+
}
|
323 |
+
|
324 |
+
// The case for special objects, like std::vector<bool>, that have to be returned-by-copy:
|
325 |
+
template <typename Vector, typename Class_>
|
326 |
+
void vector_accessor(enable_if_t<vector_needs_copy<Vector>::value, Class_> &cl) {
|
327 |
+
using T = typename Vector::value_type;
|
328 |
+
using SizeType = typename Vector::size_type;
|
329 |
+
using DiffType = typename Vector::difference_type;
|
330 |
+
using ItType = typename Vector::iterator;
|
331 |
+
cl.def("__getitem__",
|
332 |
+
[](const Vector &v, DiffType i) -> T {
|
333 |
+
if (i < 0 && (i += v.size()) < 0)
|
334 |
+
throw index_error();
|
335 |
+
if ((SizeType)i >= v.size())
|
336 |
+
throw index_error();
|
337 |
+
return v[(SizeType)i];
|
338 |
+
}
|
339 |
+
);
|
340 |
+
|
341 |
+
cl.def("__iter__",
|
342 |
+
[](Vector &v) {
|
343 |
+
return make_iterator<
|
344 |
+
return_value_policy::copy, ItType, ItType, T>(
|
345 |
+
v.begin(), v.end());
|
346 |
+
},
|
347 |
+
keep_alive<0, 1>() /* Essential: keep list alive while iterator exists */
|
348 |
+
);
|
349 |
+
}
|
350 |
+
|
351 |
+
template <typename Vector, typename Class_> auto vector_if_insertion_operator(Class_ &cl, std::string const &name)
|
352 |
+
-> decltype(std::declval<std::ostream&>() << std::declval<typename Vector::value_type>(), void()) {
|
353 |
+
using size_type = typename Vector::size_type;
|
354 |
+
|
355 |
+
cl.def("__repr__",
|
356 |
+
[name](Vector &v) {
|
357 |
+
std::ostringstream s;
|
358 |
+
s << name << '[';
|
359 |
+
for (size_type i=0; i < v.size(); ++i) {
|
360 |
+
s << v[i];
|
361 |
+
if (i != v.size() - 1)
|
362 |
+
s << ", ";
|
363 |
+
}
|
364 |
+
s << ']';
|
365 |
+
return s.str();
|
366 |
+
},
|
367 |
+
"Return the canonical string representation of this list."
|
368 |
+
);
|
369 |
+
}
|
370 |
+
|
371 |
+
// Provide the buffer interface for vectors if we have data() and we have a format for it
|
372 |
+
// 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
|
373 |
+
template <typename Vector, typename = void>
|
374 |
+
struct vector_has_data_and_format : std::false_type {};
|
375 |
+
template <typename Vector>
|
376 |
+
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 {};
|
377 |
+
|
378 |
+
// [workaround(intel)] Separate function required here
|
379 |
+
// Workaround as the Intel compiler does not compile the enable_if_t part below
|
380 |
+
// (tested with icc (ICC) 2021.1 Beta 20200827)
|
381 |
+
template <typename... Args>
|
382 |
+
constexpr bool args_any_are_buffer() {
|
383 |
+
return detail::any_of<std::is_same<Args, buffer_protocol>...>::value;
|
384 |
+
}
|
385 |
+
|
386 |
+
// [workaround(intel)] Separate function required here
|
387 |
+
// [workaround(msvc)] Can't use constexpr bool in return type
|
388 |
+
|
389 |
+
// Add the buffer interface to a vector
|
390 |
+
template <typename Vector, typename Class_, typename... Args>
|
391 |
+
void vector_buffer_impl(Class_& cl, std::true_type) {
|
392 |
+
using T = typename Vector::value_type;
|
393 |
+
|
394 |
+
static_assert(vector_has_data_and_format<Vector>::value, "There is not an appropriate format descriptor for this vector");
|
395 |
+
|
396 |
+
// 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
|
397 |
+
format_descriptor<T>::format();
|
398 |
+
|
399 |
+
cl.def_buffer([](Vector& v) -> buffer_info {
|
400 |
+
return buffer_info(v.data(), static_cast<ssize_t>(sizeof(T)), format_descriptor<T>::format(), 1, {v.size()}, {sizeof(T)});
|
401 |
+
});
|
402 |
+
|
403 |
+
cl.def(init([](const buffer &buf) {
|
404 |
+
auto info = buf.request();
|
405 |
+
if (info.ndim != 1 || info.strides[0] % static_cast<ssize_t>(sizeof(T)))
|
406 |
+
throw type_error("Only valid 1D buffers can be copied to a vector");
|
407 |
+
if (!detail::compare_buffer_info<T>::compare(info) || (ssize_t) sizeof(T) != info.itemsize)
|
408 |
+
throw type_error("Format mismatch (Python: " + info.format + " C++: " + format_descriptor<T>::format() + ")");
|
409 |
+
|
410 |
+
T *p = static_cast<T*>(info.ptr);
|
411 |
+
ssize_t step = info.strides[0] / static_cast<ssize_t>(sizeof(T));
|
412 |
+
T *end = p + info.shape[0] * step;
|
413 |
+
if (step == 1) {
|
414 |
+
return Vector(p, end);
|
415 |
+
}
|
416 |
+
Vector vec;
|
417 |
+
vec.reserve((size_t) info.shape[0]);
|
418 |
+
for (; p != end; p += step)
|
419 |
+
vec.push_back(*p);
|
420 |
+
return vec;
|
421 |
+
|
422 |
+
}));
|
423 |
+
|
424 |
+
return;
|
425 |
+
}
|
426 |
+
|
427 |
+
template <typename Vector, typename Class_, typename... Args>
|
428 |
+
void vector_buffer_impl(Class_&, std::false_type) {}
|
429 |
+
|
430 |
+
template <typename Vector, typename Class_, typename... Args>
|
431 |
+
void vector_buffer(Class_& cl) {
|
432 |
+
vector_buffer_impl<Vector, Class_, Args...>(cl, detail::any_of<std::is_same<Args, buffer_protocol>...>{});
|
433 |
+
}
|
434 |
+
|
435 |
+
PYBIND11_NAMESPACE_END(detail)
|
436 |
+
|
437 |
+
//
|
438 |
+
// std::vector
|
439 |
+
//
|
440 |
+
template <typename Vector, typename holder_type = std::unique_ptr<Vector>, typename... Args>
|
441 |
+
class_<Vector, holder_type> bind_vector(handle scope, std::string const &name, Args&&... args) {
|
442 |
+
using Class_ = class_<Vector, holder_type>;
|
443 |
+
|
444 |
+
// If the value_type is unregistered (e.g. a converting type) or is itself registered
|
445 |
+
// module-local then make the vector binding module-local as well:
|
446 |
+
using vtype = typename Vector::value_type;
|
447 |
+
auto vtype_info = detail::get_type_info(typeid(vtype));
|
448 |
+
bool local = !vtype_info || vtype_info->module_local;
|
449 |
+
|
450 |
+
Class_ cl(scope, name.c_str(), pybind11::module_local(local), std::forward<Args>(args)...);
|
451 |
+
|
452 |
+
// Declare the buffer interface if a buffer_protocol() is passed in
|
453 |
+
detail::vector_buffer<Vector, Class_, Args...>(cl);
|
454 |
+
|
455 |
+
cl.def(init<>());
|
456 |
+
|
457 |
+
// Register copy constructor (if possible)
|
458 |
+
detail::vector_if_copy_constructible<Vector, Class_>(cl);
|
459 |
+
|
460 |
+
// Register comparison-related operators and functions (if possible)
|
461 |
+
detail::vector_if_equal_operator<Vector, Class_>(cl);
|
462 |
+
|
463 |
+
// Register stream insertion operator (if possible)
|
464 |
+
detail::vector_if_insertion_operator<Vector, Class_>(cl, name);
|
465 |
+
|
466 |
+
// Modifiers require copyable vector value type
|
467 |
+
detail::vector_modifiers<Vector, Class_>(cl);
|
468 |
+
|
469 |
+
// Accessor and iterator; return by value if copyable, otherwise we return by ref + keep-alive
|
470 |
+
detail::vector_accessor<Vector, Class_>(cl);
|
471 |
+
|
472 |
+
cl.def("__bool__",
|
473 |
+
[](const Vector &v) -> bool {
|
474 |
+
return !v.empty();
|
475 |
+
},
|
476 |
+
"Check whether the list is nonempty"
|
477 |
+
);
|
478 |
+
|
479 |
+
cl.def("__len__", &Vector::size);
|
480 |
+
|
481 |
+
|
482 |
+
|
483 |
+
|
484 |
+
#if 0
|
485 |
+
// C++ style functions deprecated, leaving it here as an example
|
486 |
+
cl.def(init<size_type>());
|
487 |
+
|
488 |
+
cl.def("resize",
|
489 |
+
(void (Vector::*) (size_type count)) & Vector::resize,
|
490 |
+
"changes the number of elements stored");
|
491 |
+
|
492 |
+
cl.def("erase",
|
493 |
+
[](Vector &v, SizeType i) {
|
494 |
+
if (i >= v.size())
|
495 |
+
throw index_error();
|
496 |
+
v.erase(v.begin() + i);
|
497 |
+
}, "erases element at index ``i``");
|
498 |
+
|
499 |
+
cl.def("empty", &Vector::empty, "checks whether the container is empty");
|
500 |
+
cl.def("size", &Vector::size, "returns the number of elements");
|
501 |
+
cl.def("push_back", (void (Vector::*)(const T&)) &Vector::push_back, "adds an element to the end");
|
502 |
+
cl.def("pop_back", &Vector::pop_back, "removes the last element");
|
503 |
+
|
504 |
+
cl.def("max_size", &Vector::max_size, "returns the maximum possible number of elements");
|
505 |
+
cl.def("reserve", &Vector::reserve, "reserves storage");
|
506 |
+
cl.def("capacity", &Vector::capacity, "returns the number of elements that can be held in currently allocated storage");
|
507 |
+
cl.def("shrink_to_fit", &Vector::shrink_to_fit, "reduces memory usage by freeing unused memory");
|
508 |
+
|
509 |
+
cl.def("clear", &Vector::clear, "clears the contents");
|
510 |
+
cl.def("swap", &Vector::swap, "swaps the contents");
|
511 |
+
|
512 |
+
cl.def("front", [](Vector &v) {
|
513 |
+
if (v.size()) return v.front();
|
514 |
+
else throw index_error();
|
515 |
+
}, "access the first element");
|
516 |
+
|
517 |
+
cl.def("back", [](Vector &v) {
|
518 |
+
if (v.size()) return v.back();
|
519 |
+
else throw index_error();
|
520 |
+
}, "access the last element ");
|
521 |
+
|
522 |
+
#endif
|
523 |
+
|
524 |
+
return cl;
|
525 |
+
}
|
526 |
+
|
527 |
+
|
528 |
+
|
529 |
+
//
|
530 |
+
// std::map, std::unordered_map
|
531 |
+
//
|
532 |
+
|
533 |
+
PYBIND11_NAMESPACE_BEGIN(detail)
|
534 |
+
|
535 |
+
/* Fallback functions */
|
536 |
+
template <typename, typename, typename... Args> void map_if_insertion_operator(const Args &...) { }
|
537 |
+
template <typename, typename, typename... Args> void map_assignment(const Args &...) { }
|
538 |
+
|
539 |
+
// Map assignment when copy-assignable: just copy the value
|
540 |
+
template <typename Map, typename Class_>
|
541 |
+
void map_assignment(enable_if_t<is_copy_assignable<typename Map::mapped_type>::value, Class_> &cl) {
|
542 |
+
using KeyType = typename Map::key_type;
|
543 |
+
using MappedType = typename Map::mapped_type;
|
544 |
+
|
545 |
+
cl.def("__setitem__",
|
546 |
+
[](Map &m, const KeyType &k, const MappedType &v) {
|
547 |
+
auto it = m.find(k);
|
548 |
+
if (it != m.end()) it->second = v;
|
549 |
+
else m.emplace(k, v);
|
550 |
+
}
|
551 |
+
);
|
552 |
+
}
|
553 |
+
|
554 |
+
// Not copy-assignable, but still copy-constructible: we can update the value by erasing and reinserting
|
555 |
+
template<typename Map, typename Class_>
|
556 |
+
void map_assignment(enable_if_t<
|
557 |
+
!is_copy_assignable<typename Map::mapped_type>::value &&
|
558 |
+
is_copy_constructible<typename Map::mapped_type>::value,
|
559 |
+
Class_> &cl) {
|
560 |
+
using KeyType = typename Map::key_type;
|
561 |
+
using MappedType = typename Map::mapped_type;
|
562 |
+
|
563 |
+
cl.def("__setitem__",
|
564 |
+
[](Map &m, const KeyType &k, const MappedType &v) {
|
565 |
+
// We can't use m[k] = v; because value type might not be default constructable
|
566 |
+
auto r = m.emplace(k, v);
|
567 |
+
if (!r.second) {
|
568 |
+
// value type is not copy assignable so the only way to insert it is to erase it first...
|
569 |
+
m.erase(r.first);
|
570 |
+
m.emplace(k, v);
|
571 |
+
}
|
572 |
+
}
|
573 |
+
);
|
574 |
+
}
|
575 |
+
|
576 |
+
|
577 |
+
template <typename Map, typename Class_> auto map_if_insertion_operator(Class_ &cl, std::string const &name)
|
578 |
+
-> decltype(std::declval<std::ostream&>() << std::declval<typename Map::key_type>() << std::declval<typename Map::mapped_type>(), void()) {
|
579 |
+
|
580 |
+
cl.def("__repr__",
|
581 |
+
[name](Map &m) {
|
582 |
+
std::ostringstream s;
|
583 |
+
s << name << '{';
|
584 |
+
bool f = false;
|
585 |
+
for (auto const &kv : m) {
|
586 |
+
if (f)
|
587 |
+
s << ", ";
|
588 |
+
s << kv.first << ": " << kv.second;
|
589 |
+
f = true;
|
590 |
+
}
|
591 |
+
s << '}';
|
592 |
+
return s.str();
|
593 |
+
},
|
594 |
+
"Return the canonical string representation of this map."
|
595 |
+
);
|
596 |
+
}
|
597 |
+
|
598 |
+
|
599 |
+
PYBIND11_NAMESPACE_END(detail)
|
600 |
+
|
601 |
+
template <typename Map, typename holder_type = std::unique_ptr<Map>, typename... Args>
|
602 |
+
class_<Map, holder_type> bind_map(handle scope, const std::string &name, Args&&... args) {
|
603 |
+
using KeyType = typename Map::key_type;
|
604 |
+
using MappedType = typename Map::mapped_type;
|
605 |
+
using Class_ = class_<Map, holder_type>;
|
606 |
+
|
607 |
+
// If either type is a non-module-local bound type then make the map binding non-local as well;
|
608 |
+
// otherwise (e.g. both types are either module-local or converting) the map will be
|
609 |
+
// module-local.
|
610 |
+
auto tinfo = detail::get_type_info(typeid(MappedType));
|
611 |
+
bool local = !tinfo || tinfo->module_local;
|
612 |
+
if (local) {
|
613 |
+
tinfo = detail::get_type_info(typeid(KeyType));
|
614 |
+
local = !tinfo || tinfo->module_local;
|
615 |
+
}
|
616 |
+
|
617 |
+
Class_ cl(scope, name.c_str(), pybind11::module_local(local), std::forward<Args>(args)...);
|
618 |
+
|
619 |
+
cl.def(init<>());
|
620 |
+
|
621 |
+
// Register stream insertion operator (if possible)
|
622 |
+
detail::map_if_insertion_operator<Map, Class_>(cl, name);
|
623 |
+
|
624 |
+
cl.def("__bool__",
|
625 |
+
[](const Map &m) -> bool { return !m.empty(); },
|
626 |
+
"Check whether the map is nonempty"
|
627 |
+
);
|
628 |
+
|
629 |
+
cl.def("__iter__",
|
630 |
+
[](Map &m) { return make_key_iterator(m.begin(), m.end()); },
|
631 |
+
keep_alive<0, 1>() /* Essential: keep list alive while iterator exists */
|
632 |
+
);
|
633 |
+
|
634 |
+
cl.def("items",
|
635 |
+
[](Map &m) { return make_iterator(m.begin(), m.end()); },
|
636 |
+
keep_alive<0, 1>() /* Essential: keep list alive while iterator exists */
|
637 |
+
);
|
638 |
+
|
639 |
+
cl.def("__getitem__",
|
640 |
+
[](Map &m, const KeyType &k) -> MappedType & {
|
641 |
+
auto it = m.find(k);
|
642 |
+
if (it == m.end())
|
643 |
+
throw key_error();
|
644 |
+
return it->second;
|
645 |
+
},
|
646 |
+
return_value_policy::reference_internal // ref + keepalive
|
647 |
+
);
|
648 |
+
|
649 |
+
cl.def("__contains__",
|
650 |
+
[](Map &m, const KeyType &k) -> bool {
|
651 |
+
auto it = m.find(k);
|
652 |
+
if (it == m.end())
|
653 |
+
return false;
|
654 |
+
return true;
|
655 |
+
}
|
656 |
+
);
|
657 |
+
|
658 |
+
// Assignment provided only if the type is copyable
|
659 |
+
detail::map_assignment<Map, Class_>(cl);
|
660 |
+
|
661 |
+
cl.def("__delitem__",
|
662 |
+
[](Map &m, const KeyType &k) {
|
663 |
+
auto it = m.find(k);
|
664 |
+
if (it == m.end())
|
665 |
+
throw key_error();
|
666 |
+
m.erase(it);
|
667 |
+
}
|
668 |
+
);
|
669 |
+
|
670 |
+
cl.def("__len__", &Map::size);
|
671 |
+
|
672 |
+
return cl;
|
673 |
+
}
|
674 |
+
|
675 |
+
PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)
|
third-party/DPVO/Pangolin/components/pango_python/pybind11/noxfile.py
ADDED
@@ -0,0 +1,87 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import nox
|
2 |
+
|
3 |
+
|
4 |
+
nox.options.sessions = ["lint", "tests", "tests_packaging"]
|
5 |
+
|
6 |
+
|
7 |
+
@nox.session(reuse_venv=True)
|
8 |
+
def lint(session: nox.Session) -> None:
|
9 |
+
"""
|
10 |
+
Lint the codebase (except for clang-format/tidy).
|
11 |
+
"""
|
12 |
+
session.install("pre-commit")
|
13 |
+
session.run("pre-commit", "run", "-a")
|
14 |
+
|
15 |
+
|
16 |
+
@nox.session
|
17 |
+
def tests(session: nox.Session) -> None:
|
18 |
+
"""
|
19 |
+
Run the tests (requires a compiler).
|
20 |
+
"""
|
21 |
+
tmpdir = session.create_tmp()
|
22 |
+
session.install("pytest", "cmake")
|
23 |
+
session.run(
|
24 |
+
"cmake",
|
25 |
+
"-S",
|
26 |
+
".",
|
27 |
+
"-B",
|
28 |
+
tmpdir,
|
29 |
+
"-DPYBIND11_WERROR=ON",
|
30 |
+
"-DDOWNLOAD_CATCH=ON",
|
31 |
+
"-DDOWNLOAD_EIGEN=ON",
|
32 |
+
*session.posargs
|
33 |
+
)
|
34 |
+
session.run("cmake", "--build", tmpdir)
|
35 |
+
session.run("cmake", "--build", tmpdir, "--config=Release", "--target", "check")
|
36 |
+
|
37 |
+
|
38 |
+
@nox.session
|
39 |
+
def tests_packaging(session: nox.Session) -> None:
|
40 |
+
"""
|
41 |
+
Run the packaging tests.
|
42 |
+
"""
|
43 |
+
|
44 |
+
session.install("-r", "tests/requirements.txt", "--prefer-binary")
|
45 |
+
session.run("pytest", "tests/extra_python_package")
|
46 |
+
|
47 |
+
|
48 |
+
@nox.session(reuse_venv=True)
|
49 |
+
def docs(session: nox.Session) -> None:
|
50 |
+
"""
|
51 |
+
Build the docs. Pass "serve" to serve.
|
52 |
+
"""
|
53 |
+
|
54 |
+
session.install("-r", "docs/requirements.txt")
|
55 |
+
session.chdir("docs")
|
56 |
+
|
57 |
+
if "pdf" in session.posargs:
|
58 |
+
session.run("sphinx-build", "-M", "latexpdf", ".", "_build")
|
59 |
+
return
|
60 |
+
|
61 |
+
session.run("sphinx-build", "-M", "html", ".", "_build")
|
62 |
+
|
63 |
+
if "serve" in session.posargs:
|
64 |
+
session.log("Launching docs at http://localhost:8000/ - use Ctrl-C to quit")
|
65 |
+
session.run("python", "-m", "http.server", "8000", "-d", "_build/html")
|
66 |
+
elif session.posargs:
|
67 |
+
session.error("Unsupported argument to docs")
|
68 |
+
|
69 |
+
|
70 |
+
@nox.session(reuse_venv=True)
|
71 |
+
def make_changelog(session: nox.Session) -> None:
|
72 |
+
"""
|
73 |
+
Inspect the closed issues and make entries for a changelog.
|
74 |
+
"""
|
75 |
+
session.install("ghapi", "rich")
|
76 |
+
session.run("python", "tools/make_changelog.py")
|
77 |
+
|
78 |
+
|
79 |
+
@nox.session(reuse_venv=True)
|
80 |
+
def build(session: nox.Session) -> None:
|
81 |
+
"""
|
82 |
+
Build SDists and wheels.
|
83 |
+
"""
|
84 |
+
|
85 |
+
session.install("build")
|
86 |
+
session.run("python", "-m", "build")
|
87 |
+
session.run("python", "-m", "build", env={"PYBIND11_GLOBAL_SDIST": "1"})
|
third-party/DPVO/Pangolin/components/pango_python/pybind11/pybind11/__init__.py
ADDED
@@ -0,0 +1,12 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# -*- coding: utf-8 -*-
|
2 |
+
|
3 |
+
from ._version import version_info, __version__
|
4 |
+
from .commands import get_include, get_cmake_dir
|
5 |
+
|
6 |
+
|
7 |
+
__all__ = (
|
8 |
+
"version_info",
|
9 |
+
"__version__",
|
10 |
+
"get_include",
|
11 |
+
"get_cmake_dir",
|
12 |
+
)
|
third-party/DPVO/Pangolin/components/pango_python/pybind11/pybind11/__main__.py
ADDED
@@ -0,0 +1,52 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# -*- coding: utf-8 -*-
|
2 |
+
from __future__ import print_function
|
3 |
+
|
4 |
+
import argparse
|
5 |
+
import sys
|
6 |
+
import sysconfig
|
7 |
+
|
8 |
+
from .commands import get_include, get_cmake_dir
|
9 |
+
|
10 |
+
|
11 |
+
def print_includes():
|
12 |
+
# type: () -> None
|
13 |
+
dirs = [
|
14 |
+
sysconfig.get_path("include"),
|
15 |
+
sysconfig.get_path("platinclude"),
|
16 |
+
get_include(),
|
17 |
+
]
|
18 |
+
|
19 |
+
# Make unique but preserve order
|
20 |
+
unique_dirs = []
|
21 |
+
for d in dirs:
|
22 |
+
if d and d not in unique_dirs:
|
23 |
+
unique_dirs.append(d)
|
24 |
+
|
25 |
+
print(" ".join("-I" + d for d in unique_dirs))
|
26 |
+
|
27 |
+
|
28 |
+
def main():
|
29 |
+
# type: () -> None
|
30 |
+
|
31 |
+
parser = argparse.ArgumentParser()
|
32 |
+
parser.add_argument(
|
33 |
+
"--includes",
|
34 |
+
action="store_true",
|
35 |
+
help="Include flags for both pybind11 and Python headers.",
|
36 |
+
)
|
37 |
+
parser.add_argument(
|
38 |
+
"--cmakedir",
|
39 |
+
action="store_true",
|
40 |
+
help="Print the CMake module directory, ideal for setting -Dpybind11_ROOT in CMake.",
|
41 |
+
)
|
42 |
+
args = parser.parse_args()
|
43 |
+
if not sys.argv[1:]:
|
44 |
+
parser.print_help()
|
45 |
+
if args.includes:
|
46 |
+
print_includes()
|
47 |
+
if args.cmakedir:
|
48 |
+
print(get_cmake_dir())
|
49 |
+
|
50 |
+
|
51 |
+
if __name__ == "__main__":
|
52 |
+
main()
|
third-party/DPVO/Pangolin/components/pango_python/pybind11/pybind11/_version.py
ADDED
@@ -0,0 +1,12 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# -*- coding: utf-8 -*-
|
2 |
+
|
3 |
+
|
4 |
+
def _to_int(s):
|
5 |
+
try:
|
6 |
+
return int(s)
|
7 |
+
except ValueError:
|
8 |
+
return s
|
9 |
+
|
10 |
+
|
11 |
+
__version__ = "2.7.1"
|
12 |
+
version_info = tuple(_to_int(s) for s in __version__.split("."))
|
third-party/DPVO/Pangolin/components/pango_python/pybind11/pybind11/_version.pyi
ADDED
@@ -0,0 +1,6 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from typing import Union, Tuple
|
2 |
+
|
3 |
+
def _to_int(s: str) -> Union[int, str]: ...
|
4 |
+
|
5 |
+
__version__: str
|
6 |
+
version_info: Tuple[Union[int, str], ...]
|
third-party/DPVO/Pangolin/components/pango_python/pybind11/pybind11/commands.py
ADDED
@@ -0,0 +1,22 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# -*- coding: utf-8 -*-
|
2 |
+
import os
|
3 |
+
|
4 |
+
|
5 |
+
DIR = os.path.abspath(os.path.dirname(__file__))
|
6 |
+
|
7 |
+
|
8 |
+
def get_include(user=False):
|
9 |
+
# type: (bool) -> str
|
10 |
+
installed_path = os.path.join(DIR, "include")
|
11 |
+
source_path = os.path.join(os.path.dirname(DIR), "include")
|
12 |
+
return installed_path if os.path.exists(installed_path) else source_path
|
13 |
+
|
14 |
+
|
15 |
+
def get_cmake_dir():
|
16 |
+
# type: () -> str
|
17 |
+
cmake_installed_path = os.path.join(DIR, "share", "cmake", "pybind11")
|
18 |
+
if os.path.exists(cmake_installed_path):
|
19 |
+
return cmake_installed_path
|
20 |
+
else:
|
21 |
+
msg = "pybind11 not installed, installation required to access the CMake files"
|
22 |
+
raise ImportError(msg)
|
third-party/DPVO/Pangolin/components/pango_python/pybind11/pybind11/py.typed
ADDED
File without changes
|
third-party/DPVO/Pangolin/components/pango_python/pybind11/pybind11/setup_helpers.py
ADDED
@@ -0,0 +1,482 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# -*- coding: utf-8 -*-
|
2 |
+
|
3 |
+
"""
|
4 |
+
This module provides helpers for C++11+ projects using pybind11.
|
5 |
+
|
6 |
+
LICENSE:
|
7 |
+
|
8 |
+
Copyright (c) 2016 Wenzel Jakob <[email protected]>, All rights reserved.
|
9 |
+
|
10 |
+
Redistribution and use in source and binary forms, with or without
|
11 |
+
modification, are permitted provided that the following conditions are met:
|
12 |
+
|
13 |
+
1. Redistributions of source code must retain the above copyright notice, this
|
14 |
+
list of conditions and the following disclaimer.
|
15 |
+
|
16 |
+
2. Redistributions in binary form must reproduce the above copyright notice,
|
17 |
+
this list of conditions and the following disclaimer in the documentation
|
18 |
+
and/or other materials provided with the distribution.
|
19 |
+
|
20 |
+
3. Neither the name of the copyright holder nor the names of its contributors
|
21 |
+
may be used to endorse or promote products derived from this software
|
22 |
+
without specific prior written permission.
|
23 |
+
|
24 |
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
25 |
+
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
26 |
+
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
27 |
+
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
28 |
+
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
29 |
+
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
30 |
+
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
31 |
+
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
32 |
+
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
33 |
+
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
34 |
+
"""
|
35 |
+
|
36 |
+
# IMPORTANT: If you change this file in the pybind11 repo, also review
|
37 |
+
# setup_helpers.pyi for matching changes.
|
38 |
+
#
|
39 |
+
# If you copy this file in, you don't
|
40 |
+
# need the .pyi file; it's just an interface file for static type checkers.
|
41 |
+
|
42 |
+
import contextlib
|
43 |
+
import os
|
44 |
+
import shutil
|
45 |
+
import sys
|
46 |
+
import tempfile
|
47 |
+
import threading
|
48 |
+
import platform
|
49 |
+
import warnings
|
50 |
+
import sysconfig
|
51 |
+
|
52 |
+
try:
|
53 |
+
from setuptools.command.build_ext import build_ext as _build_ext
|
54 |
+
from setuptools import Extension as _Extension
|
55 |
+
except ImportError:
|
56 |
+
from distutils.command.build_ext import build_ext as _build_ext
|
57 |
+
from distutils.extension import Extension as _Extension
|
58 |
+
|
59 |
+
import distutils.errors
|
60 |
+
import distutils.ccompiler
|
61 |
+
|
62 |
+
WIN = sys.platform.startswith("win32") and "mingw" not in sysconfig.get_platform()
|
63 |
+
PY2 = sys.version_info[0] < 3
|
64 |
+
MACOS = sys.platform.startswith("darwin")
|
65 |
+
STD_TMPL = "/std:c++{}" if WIN else "-std=c++{}"
|
66 |
+
|
67 |
+
|
68 |
+
# It is recommended to use PEP 518 builds if using this module. However, this
|
69 |
+
# file explicitly supports being copied into a user's project directory
|
70 |
+
# standalone, and pulling pybind11 with the deprecated setup_requires feature.
|
71 |
+
# If you copy the file, remember to add it to your MANIFEST.in, and add the current
|
72 |
+
# directory into your path if it sits beside your setup.py.
|
73 |
+
|
74 |
+
|
75 |
+
class Pybind11Extension(_Extension):
|
76 |
+
"""
|
77 |
+
Build a C++11+ Extension module with pybind11. This automatically adds the
|
78 |
+
recommended flags when you init the extension and assumes C++ sources - you
|
79 |
+
can further modify the options yourself.
|
80 |
+
|
81 |
+
The customizations are:
|
82 |
+
|
83 |
+
* ``/EHsc`` and ``/bigobj`` on Windows
|
84 |
+
* ``stdlib=libc++`` on macOS
|
85 |
+
* ``visibility=hidden`` and ``-g0`` on Unix
|
86 |
+
|
87 |
+
Finally, you can set ``cxx_std`` via constructor or afterwards to enable
|
88 |
+
flags for C++ std, and a few extra helper flags related to the C++ standard
|
89 |
+
level. It is _highly_ recommended you either set this, or use the provided
|
90 |
+
``build_ext``, which will search for the highest supported extension for
|
91 |
+
you if the ``cxx_std`` property is not set. Do not set the ``cxx_std``
|
92 |
+
property more than once, as flags are added when you set it. Set the
|
93 |
+
property to None to disable the addition of C++ standard flags.
|
94 |
+
|
95 |
+
If you want to add pybind11 headers manually, for example for an exact
|
96 |
+
git checkout, then set ``include_pybind11=False``.
|
97 |
+
|
98 |
+
Warning: do not use property-based access to the instance on Python 2 -
|
99 |
+
this is an ugly old-style class due to Distutils.
|
100 |
+
"""
|
101 |
+
|
102 |
+
# flags are prepended, so that they can be further overridden, e.g. by
|
103 |
+
# ``extra_compile_args=["-g"]``.
|
104 |
+
|
105 |
+
def _add_cflags(self, flags):
|
106 |
+
self.extra_compile_args[:0] = flags
|
107 |
+
|
108 |
+
def _add_ldflags(self, flags):
|
109 |
+
self.extra_link_args[:0] = flags
|
110 |
+
|
111 |
+
def __init__(self, *args, **kwargs):
|
112 |
+
|
113 |
+
self._cxx_level = 0
|
114 |
+
cxx_std = kwargs.pop("cxx_std", 0)
|
115 |
+
|
116 |
+
if "language" not in kwargs:
|
117 |
+
kwargs["language"] = "c++"
|
118 |
+
|
119 |
+
include_pybind11 = kwargs.pop("include_pybind11", True)
|
120 |
+
|
121 |
+
# Can't use super here because distutils has old-style classes in
|
122 |
+
# Python 2!
|
123 |
+
_Extension.__init__(self, *args, **kwargs)
|
124 |
+
|
125 |
+
# Include the installed package pybind11 headers
|
126 |
+
if include_pybind11:
|
127 |
+
# If using setup_requires, this fails the first time - that's okay
|
128 |
+
try:
|
129 |
+
import pybind11
|
130 |
+
|
131 |
+
pyinc = pybind11.get_include()
|
132 |
+
|
133 |
+
if pyinc not in self.include_dirs:
|
134 |
+
self.include_dirs.append(pyinc)
|
135 |
+
except ImportError:
|
136 |
+
pass
|
137 |
+
|
138 |
+
# Have to use the accessor manually to support Python 2 distutils
|
139 |
+
Pybind11Extension.cxx_std.__set__(self, cxx_std)
|
140 |
+
|
141 |
+
cflags = []
|
142 |
+
ldflags = []
|
143 |
+
if WIN:
|
144 |
+
cflags += ["/EHsc", "/bigobj"]
|
145 |
+
else:
|
146 |
+
cflags += ["-fvisibility=hidden", "-g0"]
|
147 |
+
if MACOS:
|
148 |
+
cflags += ["-stdlib=libc++"]
|
149 |
+
ldflags += ["-stdlib=libc++"]
|
150 |
+
self._add_cflags(cflags)
|
151 |
+
self._add_ldflags(ldflags)
|
152 |
+
|
153 |
+
@property
|
154 |
+
def cxx_std(self):
|
155 |
+
"""
|
156 |
+
The CXX standard level. If set, will add the required flags. If left
|
157 |
+
at 0, it will trigger an automatic search when pybind11's build_ext
|
158 |
+
is used. If None, will have no effect. Besides just the flags, this
|
159 |
+
may add a register warning/error fix for Python 2 or macos-min 10.9
|
160 |
+
or 10.14.
|
161 |
+
"""
|
162 |
+
return self._cxx_level
|
163 |
+
|
164 |
+
@cxx_std.setter
|
165 |
+
def cxx_std(self, level):
|
166 |
+
|
167 |
+
if self._cxx_level:
|
168 |
+
warnings.warn("You cannot safely change the cxx_level after setting it!")
|
169 |
+
|
170 |
+
# MSVC 2015 Update 3 and later only have 14 (and later 17) modes, so
|
171 |
+
# force a valid flag here.
|
172 |
+
if WIN and level == 11:
|
173 |
+
level = 14
|
174 |
+
|
175 |
+
self._cxx_level = level
|
176 |
+
|
177 |
+
if not level:
|
178 |
+
return
|
179 |
+
|
180 |
+
cflags = [STD_TMPL.format(level)]
|
181 |
+
ldflags = []
|
182 |
+
|
183 |
+
if MACOS and "MACOSX_DEPLOYMENT_TARGET" not in os.environ:
|
184 |
+
# C++17 requires a higher min version of macOS. An earlier version
|
185 |
+
# (10.12 or 10.13) can be set manually via environment variable if
|
186 |
+
# you are careful in your feature usage, but 10.14 is the safest
|
187 |
+
# setting for general use. However, never set higher than the
|
188 |
+
# current macOS version!
|
189 |
+
current_macos = tuple(int(x) for x in platform.mac_ver()[0].split(".")[:2])
|
190 |
+
desired_macos = (10, 9) if level < 17 else (10, 14)
|
191 |
+
macos_string = ".".join(str(x) for x in min(current_macos, desired_macos))
|
192 |
+
macosx_min = "-mmacosx-version-min=" + macos_string
|
193 |
+
cflags += [macosx_min]
|
194 |
+
ldflags += [macosx_min]
|
195 |
+
|
196 |
+
if PY2:
|
197 |
+
if WIN:
|
198 |
+
# Will be ignored on MSVC 2015, where C++17 is not supported so
|
199 |
+
# this flag is not valid.
|
200 |
+
cflags += ["/wd5033"]
|
201 |
+
elif level >= 17:
|
202 |
+
cflags += ["-Wno-register"]
|
203 |
+
elif level >= 14:
|
204 |
+
cflags += ["-Wno-deprecated-register"]
|
205 |
+
|
206 |
+
self._add_cflags(cflags)
|
207 |
+
self._add_ldflags(ldflags)
|
208 |
+
|
209 |
+
|
210 |
+
# Just in case someone clever tries to multithread
|
211 |
+
tmp_chdir_lock = threading.Lock()
|
212 |
+
cpp_cache_lock = threading.Lock()
|
213 |
+
|
214 |
+
|
215 |
+
@contextlib.contextmanager
|
216 |
+
def tmp_chdir():
|
217 |
+
"Prepare and enter a temporary directory, cleanup when done"
|
218 |
+
|
219 |
+
# Threadsafe
|
220 |
+
with tmp_chdir_lock:
|
221 |
+
olddir = os.getcwd()
|
222 |
+
try:
|
223 |
+
tmpdir = tempfile.mkdtemp()
|
224 |
+
os.chdir(tmpdir)
|
225 |
+
yield tmpdir
|
226 |
+
finally:
|
227 |
+
os.chdir(olddir)
|
228 |
+
shutil.rmtree(tmpdir)
|
229 |
+
|
230 |
+
|
231 |
+
# cf http://bugs.python.org/issue26689
|
232 |
+
def has_flag(compiler, flag):
|
233 |
+
"""
|
234 |
+
Return the flag if a flag name is supported on the
|
235 |
+
specified compiler, otherwise None (can be used as a boolean).
|
236 |
+
If multiple flags are passed, return the first that matches.
|
237 |
+
"""
|
238 |
+
|
239 |
+
with tmp_chdir():
|
240 |
+
fname = "flagcheck.cpp"
|
241 |
+
with open(fname, "w") as f:
|
242 |
+
# Don't trigger -Wunused-parameter.
|
243 |
+
f.write("int main (int, char **) { return 0; }")
|
244 |
+
|
245 |
+
try:
|
246 |
+
compiler.compile([fname], extra_postargs=[flag])
|
247 |
+
except distutils.errors.CompileError:
|
248 |
+
return False
|
249 |
+
return True
|
250 |
+
|
251 |
+
|
252 |
+
# Every call will cache the result
|
253 |
+
cpp_flag_cache = None
|
254 |
+
|
255 |
+
|
256 |
+
def auto_cpp_level(compiler):
|
257 |
+
"""
|
258 |
+
Return the max supported C++ std level (17, 14, or 11). Returns latest on Windows.
|
259 |
+
"""
|
260 |
+
|
261 |
+
if WIN:
|
262 |
+
return "latest"
|
263 |
+
|
264 |
+
global cpp_flag_cache
|
265 |
+
|
266 |
+
# If this has been previously calculated with the same args, return that
|
267 |
+
with cpp_cache_lock:
|
268 |
+
if cpp_flag_cache:
|
269 |
+
return cpp_flag_cache
|
270 |
+
|
271 |
+
levels = [17, 14, 11]
|
272 |
+
|
273 |
+
for level in levels:
|
274 |
+
if has_flag(compiler, STD_TMPL.format(level)):
|
275 |
+
with cpp_cache_lock:
|
276 |
+
cpp_flag_cache = level
|
277 |
+
return level
|
278 |
+
|
279 |
+
msg = "Unsupported compiler -- at least C++11 support is needed!"
|
280 |
+
raise RuntimeError(msg)
|
281 |
+
|
282 |
+
|
283 |
+
class build_ext(_build_ext): # noqa: N801
|
284 |
+
"""
|
285 |
+
Customized build_ext that allows an auto-search for the highest supported
|
286 |
+
C++ level for Pybind11Extension. This is only needed for the auto-search
|
287 |
+
for now, and is completely optional otherwise.
|
288 |
+
"""
|
289 |
+
|
290 |
+
def build_extensions(self):
|
291 |
+
"""
|
292 |
+
Build extensions, injecting C++ std for Pybind11Extension if needed.
|
293 |
+
"""
|
294 |
+
|
295 |
+
for ext in self.extensions:
|
296 |
+
if hasattr(ext, "_cxx_level") and ext._cxx_level == 0:
|
297 |
+
# Python 2 syntax - old-style distutils class
|
298 |
+
ext.__class__.cxx_std.__set__(ext, auto_cpp_level(self.compiler))
|
299 |
+
|
300 |
+
# Python 2 doesn't allow super here, since distutils uses old-style
|
301 |
+
# classes!
|
302 |
+
_build_ext.build_extensions(self)
|
303 |
+
|
304 |
+
|
305 |
+
def intree_extensions(paths, package_dir=None):
|
306 |
+
"""
|
307 |
+
Generate Pybind11Extensions from source files directly located in a Python
|
308 |
+
source tree.
|
309 |
+
|
310 |
+
``package_dir`` behaves as in ``setuptools.setup``. If unset, the Python
|
311 |
+
package root parent is determined as the first parent directory that does
|
312 |
+
not contain an ``__init__.py`` file.
|
313 |
+
"""
|
314 |
+
exts = []
|
315 |
+
for path in paths:
|
316 |
+
if package_dir is None:
|
317 |
+
parent, _ = os.path.split(path)
|
318 |
+
while os.path.exists(os.path.join(parent, "__init__.py")):
|
319 |
+
parent, _ = os.path.split(parent)
|
320 |
+
relname, _ = os.path.splitext(os.path.relpath(path, parent))
|
321 |
+
qualified_name = relname.replace(os.path.sep, ".")
|
322 |
+
exts.append(Pybind11Extension(qualified_name, [path]))
|
323 |
+
else:
|
324 |
+
found = False
|
325 |
+
for prefix, parent in package_dir.items():
|
326 |
+
if path.startswith(parent):
|
327 |
+
found = True
|
328 |
+
relname, _ = os.path.splitext(os.path.relpath(path, parent))
|
329 |
+
qualified_name = relname.replace(os.path.sep, ".")
|
330 |
+
if prefix:
|
331 |
+
qualified_name = prefix + "." + qualified_name
|
332 |
+
exts.append(Pybind11Extension(qualified_name, [path]))
|
333 |
+
if not found:
|
334 |
+
raise ValueError(
|
335 |
+
"path {} is not a child of any of the directories listed "
|
336 |
+
"in 'package_dir' ({})".format(path, package_dir)
|
337 |
+
)
|
338 |
+
return exts
|
339 |
+
|
340 |
+
|
341 |
+
def naive_recompile(obj, src):
|
342 |
+
"""
|
343 |
+
This will recompile only if the source file changes. It does not check
|
344 |
+
header files, so a more advanced function or Ccache is better if you have
|
345 |
+
editable header files in your package.
|
346 |
+
"""
|
347 |
+
return os.stat(obj).st_mtime < os.stat(src).st_mtime
|
348 |
+
|
349 |
+
|
350 |
+
def no_recompile(obg, src):
|
351 |
+
"""
|
352 |
+
This is the safest but slowest choice (and is the default) - will always
|
353 |
+
recompile sources.
|
354 |
+
"""
|
355 |
+
return True
|
356 |
+
|
357 |
+
|
358 |
+
# Optional parallel compile utility
|
359 |
+
# inspired by: http://stackoverflow.com/questions/11013851/speeding-up-build-process-with-distutils
|
360 |
+
# and: https://github.com/tbenthompson/cppimport/blob/stable/cppimport/build_module.py
|
361 |
+
# and NumPy's parallel distutils module:
|
362 |
+
# https://github.com/numpy/numpy/blob/master/numpy/distutils/ccompiler.py
|
363 |
+
class ParallelCompile(object):
|
364 |
+
"""
|
365 |
+
Make a parallel compile function. Inspired by
|
366 |
+
numpy.distutils.ccompiler.CCompiler_compile and cppimport.
|
367 |
+
|
368 |
+
This takes several arguments that allow you to customize the compile
|
369 |
+
function created:
|
370 |
+
|
371 |
+
envvar:
|
372 |
+
Set an environment variable to control the compilation threads, like
|
373 |
+
NPY_NUM_BUILD_JOBS
|
374 |
+
default:
|
375 |
+
0 will automatically multithread, or 1 will only multithread if the
|
376 |
+
envvar is set.
|
377 |
+
max:
|
378 |
+
The limit for automatic multithreading if non-zero
|
379 |
+
needs_recompile:
|
380 |
+
A function of (obj, src) that returns True when recompile is needed. No
|
381 |
+
effect in isolated mode; use ccache instead, see
|
382 |
+
https://github.com/matplotlib/matplotlib/issues/1507/
|
383 |
+
|
384 |
+
To use::
|
385 |
+
|
386 |
+
ParallelCompile("NPY_NUM_BUILD_JOBS").install()
|
387 |
+
|
388 |
+
or::
|
389 |
+
|
390 |
+
with ParallelCompile("NPY_NUM_BUILD_JOBS"):
|
391 |
+
setup(...)
|
392 |
+
|
393 |
+
By default, this assumes all files need to be recompiled. A smarter
|
394 |
+
function can be provided via needs_recompile. If the output has not yet
|
395 |
+
been generated, the compile will always run, and this function is not
|
396 |
+
called.
|
397 |
+
"""
|
398 |
+
|
399 |
+
__slots__ = ("envvar", "default", "max", "_old", "needs_recompile")
|
400 |
+
|
401 |
+
def __init__(self, envvar=None, default=0, max=0, needs_recompile=no_recompile):
|
402 |
+
self.envvar = envvar
|
403 |
+
self.default = default
|
404 |
+
self.max = max
|
405 |
+
self.needs_recompile = needs_recompile
|
406 |
+
self._old = []
|
407 |
+
|
408 |
+
def function(self):
|
409 |
+
"""
|
410 |
+
Builds a function object usable as distutils.ccompiler.CCompiler.compile.
|
411 |
+
"""
|
412 |
+
|
413 |
+
def compile_function(
|
414 |
+
compiler,
|
415 |
+
sources,
|
416 |
+
output_dir=None,
|
417 |
+
macros=None,
|
418 |
+
include_dirs=None,
|
419 |
+
debug=0,
|
420 |
+
extra_preargs=None,
|
421 |
+
extra_postargs=None,
|
422 |
+
depends=None,
|
423 |
+
):
|
424 |
+
|
425 |
+
# These lines are directly from distutils.ccompiler.CCompiler
|
426 |
+
macros, objects, extra_postargs, pp_opts, build = compiler._setup_compile(
|
427 |
+
output_dir, macros, include_dirs, sources, depends, extra_postargs
|
428 |
+
)
|
429 |
+
cc_args = compiler._get_cc_args(pp_opts, debug, extra_preargs)
|
430 |
+
|
431 |
+
# The number of threads; start with default.
|
432 |
+
threads = self.default
|
433 |
+
|
434 |
+
# Determine the number of compilation threads, unless set by an environment variable.
|
435 |
+
if self.envvar is not None:
|
436 |
+
threads = int(os.environ.get(self.envvar, self.default))
|
437 |
+
|
438 |
+
def _single_compile(obj):
|
439 |
+
try:
|
440 |
+
src, ext = build[obj]
|
441 |
+
except KeyError:
|
442 |
+
return
|
443 |
+
|
444 |
+
if not os.path.exists(obj) or self.needs_recompile(obj, src):
|
445 |
+
compiler._compile(obj, src, ext, cc_args, extra_postargs, pp_opts)
|
446 |
+
|
447 |
+
try:
|
448 |
+
# Importing .synchronize checks for platforms that have some multiprocessing
|
449 |
+
# capabilities but lack semaphores, such as AWS Lambda and Android Termux.
|
450 |
+
import multiprocessing.synchronize
|
451 |
+
from multiprocessing.pool import ThreadPool
|
452 |
+
except ImportError:
|
453 |
+
threads = 1
|
454 |
+
|
455 |
+
if threads == 0:
|
456 |
+
try:
|
457 |
+
threads = multiprocessing.cpu_count()
|
458 |
+
threads = self.max if self.max and self.max < threads else threads
|
459 |
+
except NotImplementedError:
|
460 |
+
threads = 1
|
461 |
+
|
462 |
+
if threads > 1:
|
463 |
+
for _ in ThreadPool(threads).imap_unordered(_single_compile, objects):
|
464 |
+
pass
|
465 |
+
else:
|
466 |
+
for ob in objects:
|
467 |
+
_single_compile(ob)
|
468 |
+
|
469 |
+
return objects
|
470 |
+
|
471 |
+
return compile_function
|
472 |
+
|
473 |
+
def install(self):
|
474 |
+
distutils.ccompiler.CCompiler.compile = self.function()
|
475 |
+
return self
|
476 |
+
|
477 |
+
def __enter__(self):
|
478 |
+
self._old.append(distutils.ccompiler.CCompiler.compile)
|
479 |
+
return self.install()
|
480 |
+
|
481 |
+
def __exit__(self, *args):
|
482 |
+
distutils.ccompiler.CCompiler.compile = self._old.pop()
|
third-party/DPVO/Pangolin/components/pango_python/pybind11/pybind11/setup_helpers.pyi
ADDED
@@ -0,0 +1,64 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# IMPORTANT: Should stay in sync with setup_helpers.py (mostly checked by CI /
|
2 |
+
# pre-commit).
|
3 |
+
|
4 |
+
from typing import Any, Callable, Dict, Iterator, List, Optional, Type, TypeVar, Union
|
5 |
+
from types import TracebackType
|
6 |
+
|
7 |
+
from distutils.command.build_ext import build_ext as _build_ext # type: ignore
|
8 |
+
from distutils.extension import Extension as _Extension
|
9 |
+
import distutils.ccompiler
|
10 |
+
import contextlib
|
11 |
+
|
12 |
+
WIN: bool
|
13 |
+
PY2: bool
|
14 |
+
MACOS: bool
|
15 |
+
STD_TMPL: str
|
16 |
+
|
17 |
+
class Pybind11Extension(_Extension):
|
18 |
+
def _add_cflags(self, *flags: str) -> None: ...
|
19 |
+
def _add_lflags(self, *flags: str) -> None: ...
|
20 |
+
def __init__(
|
21 |
+
self, *args: Any, cxx_std: int = 0, language: str = "c++", **kwargs: Any
|
22 |
+
) -> None: ...
|
23 |
+
@property
|
24 |
+
def cxx_std(self) -> int: ...
|
25 |
+
@cxx_std.setter
|
26 |
+
def cxx_std(self, level: int) -> None: ...
|
27 |
+
|
28 |
+
@contextlib.contextmanager
|
29 |
+
def tmp_chdir() -> Iterator[str]: ...
|
30 |
+
def has_flag(compiler: distutils.ccompiler.CCompiler, flag: str) -> bool: ...
|
31 |
+
def auto_cpp_level(compiler: distutils.ccompiler.CCompiler) -> Union[int, str]: ...
|
32 |
+
|
33 |
+
class build_ext(_build_ext): # type: ignore
|
34 |
+
def build_extensions(self) -> None: ...
|
35 |
+
|
36 |
+
def intree_extensions(
|
37 |
+
paths: Iterator[str], package_dir: Optional[Dict[str, str]] = None
|
38 |
+
) -> List[Pybind11Extension]: ...
|
39 |
+
def no_recompile(obj: str, src: str) -> bool: ...
|
40 |
+
def naive_recompile(obj: str, src: str) -> bool: ...
|
41 |
+
|
42 |
+
T = TypeVar("T", bound="ParallelCompile")
|
43 |
+
|
44 |
+
class ParallelCompile:
|
45 |
+
envvar: Optional[str]
|
46 |
+
default: int
|
47 |
+
max: int
|
48 |
+
needs_recompile: Callable[[str, str], bool]
|
49 |
+
def __init__(
|
50 |
+
self,
|
51 |
+
envvar: Optional[str] = None,
|
52 |
+
default: int = 0,
|
53 |
+
max: int = 0,
|
54 |
+
needs_recompile: Callable[[str, str], bool] = no_recompile,
|
55 |
+
) -> None: ...
|
56 |
+
def function(self) -> Any: ...
|
57 |
+
def install(self: T) -> T: ...
|
58 |
+
def __enter__(self: T) -> T: ...
|
59 |
+
def __exit__(
|
60 |
+
self,
|
61 |
+
exc_type: Optional[Type[BaseException]],
|
62 |
+
exc_value: Optional[BaseException],
|
63 |
+
traceback: Optional[TracebackType],
|
64 |
+
) -> None: ...
|
third-party/DPVO/Pangolin/components/pango_python/pybind11/pyproject.toml
ADDED
@@ -0,0 +1,35 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
[build-system]
|
2 |
+
requires = ["setuptools>=42", "wheel", "cmake>=3.18", "ninja"]
|
3 |
+
build-backend = "setuptools.build_meta"
|
4 |
+
|
5 |
+
[tool.check-manifest]
|
6 |
+
ignore = [
|
7 |
+
"tests/**",
|
8 |
+
"docs/**",
|
9 |
+
"tools/**",
|
10 |
+
"include/**",
|
11 |
+
".*",
|
12 |
+
"pybind11/include/**",
|
13 |
+
"pybind11/share/**",
|
14 |
+
"CMakeLists.txt",
|
15 |
+
"noxfile.py",
|
16 |
+
]
|
17 |
+
|
18 |
+
[tool.mypy]
|
19 |
+
files = "pybind11"
|
20 |
+
python_version = "2.7"
|
21 |
+
warn_unused_configs = true
|
22 |
+
|
23 |
+
disallow_any_generics = true
|
24 |
+
disallow_subclassing_any = true
|
25 |
+
disallow_untyped_calls = true
|
26 |
+
disallow_untyped_defs = true
|
27 |
+
disallow_incomplete_defs = true
|
28 |
+
check_untyped_defs = true
|
29 |
+
disallow_untyped_decorators = true
|
30 |
+
no_implicit_optional = true
|
31 |
+
warn_redundant_casts = true
|
32 |
+
warn_unused_ignores = true
|
33 |
+
warn_return_any = true
|
34 |
+
no_implicit_reexport = true
|
35 |
+
strict_equality = true
|
third-party/DPVO/Pangolin/components/pango_python/pybind11/setup.cfg
ADDED
@@ -0,0 +1,56 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
[metadata]
|
2 |
+
long_description = file: README.rst
|
3 |
+
long_description_content_type = text/x-rst
|
4 |
+
description = Seamless operability between C++11 and Python
|
5 |
+
author = Wenzel Jakob
|
6 |
+
author_email = [email protected]
|
7 |
+
url = https://github.com/pybind/pybind11
|
8 |
+
license = BSD
|
9 |
+
|
10 |
+
classifiers =
|
11 |
+
Development Status :: 5 - Production/Stable
|
12 |
+
Intended Audience :: Developers
|
13 |
+
Topic :: Software Development :: Libraries :: Python Modules
|
14 |
+
Topic :: Utilities
|
15 |
+
Programming Language :: C++
|
16 |
+
Programming Language :: Python :: 2.7
|
17 |
+
Programming Language :: Python :: 3
|
18 |
+
Programming Language :: Python :: 3.5
|
19 |
+
Programming Language :: Python :: 3.6
|
20 |
+
Programming Language :: Python :: 3.7
|
21 |
+
Programming Language :: Python :: 3.8
|
22 |
+
Programming Language :: Python :: 3.9
|
23 |
+
Programming Language :: Python :: 3.10
|
24 |
+
License :: OSI Approved :: BSD License
|
25 |
+
Programming Language :: Python :: Implementation :: PyPy
|
26 |
+
Programming Language :: Python :: Implementation :: CPython
|
27 |
+
Programming Language :: C++
|
28 |
+
Topic :: Software Development :: Libraries :: Python Modules
|
29 |
+
|
30 |
+
keywords =
|
31 |
+
C++11
|
32 |
+
Python bindings
|
33 |
+
|
34 |
+
[options]
|
35 |
+
python_requires = >=2.7, !=3.0, !=3.1, !=3.2, !=3.3, !=3.4
|
36 |
+
zip_safe = False
|
37 |
+
|
38 |
+
[bdist_wheel]
|
39 |
+
universal=1
|
40 |
+
|
41 |
+
|
42 |
+
[flake8]
|
43 |
+
max-line-length = 99
|
44 |
+
show_source = True
|
45 |
+
exclude = .git, __pycache__, build, dist, docs, tools, venv
|
46 |
+
ignore =
|
47 |
+
# required for pretty matrix formatting: multiple spaces after `,` and `[`
|
48 |
+
E201, E241, W504,
|
49 |
+
# camelcase 'cPickle' imported as lowercase 'pickle'
|
50 |
+
N813
|
51 |
+
# Black conflict
|
52 |
+
W503, E203
|
53 |
+
|
54 |
+
|
55 |
+
[tool:pytest]
|
56 |
+
timeout = 300
|
third-party/DPVO/Pangolin/components/pango_python/pybind11/setup.py
ADDED
@@ -0,0 +1,155 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
#!/usr/bin/env python
|
2 |
+
# -*- coding: utf-8 -*-
|
3 |
+
|
4 |
+
# Setup script for PyPI; use CMakeFile.txt to build extension modules
|
5 |
+
|
6 |
+
import contextlib
|
7 |
+
import os
|
8 |
+
import re
|
9 |
+
import shutil
|
10 |
+
import string
|
11 |
+
import subprocess
|
12 |
+
import sys
|
13 |
+
import tempfile
|
14 |
+
import io
|
15 |
+
|
16 |
+
import setuptools.command.sdist
|
17 |
+
|
18 |
+
DIR = os.path.abspath(os.path.dirname(__file__))
|
19 |
+
VERSION_REGEX = re.compile(
|
20 |
+
r"^\s*#\s*define\s+PYBIND11_VERSION_([A-Z]+)\s+(.*)$", re.MULTILINE
|
21 |
+
)
|
22 |
+
|
23 |
+
|
24 |
+
def build_expected_version_hex(matches):
|
25 |
+
patch_level_serial = matches["PATCH"]
|
26 |
+
serial = None
|
27 |
+
try:
|
28 |
+
major = int(matches["MAJOR"])
|
29 |
+
minor = int(matches["MINOR"])
|
30 |
+
flds = patch_level_serial.split(".")
|
31 |
+
if flds:
|
32 |
+
patch = int(flds[0])
|
33 |
+
level = None
|
34 |
+
if len(flds) == 1:
|
35 |
+
level = "0"
|
36 |
+
serial = 0
|
37 |
+
elif len(flds) == 2:
|
38 |
+
level_serial = flds[1]
|
39 |
+
for level in ("a", "b", "c", "dev"):
|
40 |
+
if level_serial.startswith(level):
|
41 |
+
serial = int(level_serial[len(level) :])
|
42 |
+
break
|
43 |
+
except ValueError:
|
44 |
+
pass
|
45 |
+
if serial is None:
|
46 |
+
msg = 'Invalid PYBIND11_VERSION_PATCH: "{}"'.format(patch_level_serial)
|
47 |
+
raise RuntimeError(msg)
|
48 |
+
return "0x{:02x}{:02x}{:02x}{}{:x}".format(
|
49 |
+
major, minor, patch, level[:1].upper(), serial
|
50 |
+
)
|
51 |
+
|
52 |
+
|
53 |
+
# PYBIND11_GLOBAL_SDIST will build a different sdist, with the python-headers
|
54 |
+
# files, and the sys.prefix files (CMake and headers).
|
55 |
+
|
56 |
+
global_sdist = os.environ.get("PYBIND11_GLOBAL_SDIST", False)
|
57 |
+
|
58 |
+
setup_py = "tools/setup_global.py.in" if global_sdist else "tools/setup_main.py.in"
|
59 |
+
extra_cmd = 'cmdclass["sdist"] = SDist\n'
|
60 |
+
|
61 |
+
to_src = (
|
62 |
+
("pyproject.toml", "tools/pyproject.toml"),
|
63 |
+
("setup.py", setup_py),
|
64 |
+
)
|
65 |
+
|
66 |
+
# Read the listed version
|
67 |
+
with open("pybind11/_version.py") as f:
|
68 |
+
code = compile(f.read(), "pybind11/_version.py", "exec")
|
69 |
+
loc = {}
|
70 |
+
exec(code, loc)
|
71 |
+
version = loc["__version__"]
|
72 |
+
|
73 |
+
# Verify that the version matches the one in C++
|
74 |
+
with io.open("include/pybind11/detail/common.h", encoding="utf8") as f:
|
75 |
+
matches = dict(VERSION_REGEX.findall(f.read()))
|
76 |
+
cpp_version = "{MAJOR}.{MINOR}.{PATCH}".format(**matches)
|
77 |
+
if version != cpp_version:
|
78 |
+
msg = "Python version {} does not match C++ version {}!".format(
|
79 |
+
version, cpp_version
|
80 |
+
)
|
81 |
+
raise RuntimeError(msg)
|
82 |
+
|
83 |
+
version_hex = matches.get("HEX", "MISSING")
|
84 |
+
expected_version_hex = build_expected_version_hex(matches)
|
85 |
+
if version_hex != expected_version_hex:
|
86 |
+
msg = "PYBIND11_VERSION_HEX {} does not match expected value {}!".format(
|
87 |
+
version_hex,
|
88 |
+
expected_version_hex,
|
89 |
+
)
|
90 |
+
raise RuntimeError(msg)
|
91 |
+
|
92 |
+
|
93 |
+
def get_and_replace(filename, binary=False, **opts):
|
94 |
+
with open(filename, "rb" if binary else "r") as f:
|
95 |
+
contents = f.read()
|
96 |
+
# Replacement has to be done on text in Python 3 (both work in Python 2)
|
97 |
+
if binary:
|
98 |
+
return string.Template(contents.decode()).substitute(opts).encode()
|
99 |
+
else:
|
100 |
+
return string.Template(contents).substitute(opts)
|
101 |
+
|
102 |
+
|
103 |
+
# Use our input files instead when making the SDist (and anything that depends
|
104 |
+
# on it, like a wheel)
|
105 |
+
class SDist(setuptools.command.sdist.sdist):
|
106 |
+
def make_release_tree(self, base_dir, files):
|
107 |
+
setuptools.command.sdist.sdist.make_release_tree(self, base_dir, files)
|
108 |
+
|
109 |
+
for to, src in to_src:
|
110 |
+
txt = get_and_replace(src, binary=True, version=version, extra_cmd="")
|
111 |
+
|
112 |
+
dest = os.path.join(base_dir, to)
|
113 |
+
|
114 |
+
# This is normally linked, so unlink before writing!
|
115 |
+
os.unlink(dest)
|
116 |
+
with open(dest, "wb") as f:
|
117 |
+
f.write(txt)
|
118 |
+
|
119 |
+
|
120 |
+
# Backport from Python 3
|
121 |
+
@contextlib.contextmanager
|
122 |
+
def TemporaryDirectory(): # noqa: N802
|
123 |
+
"Prepare a temporary directory, cleanup when done"
|
124 |
+
try:
|
125 |
+
tmpdir = tempfile.mkdtemp()
|
126 |
+
yield tmpdir
|
127 |
+
finally:
|
128 |
+
shutil.rmtree(tmpdir)
|
129 |
+
|
130 |
+
|
131 |
+
# Remove the CMake install directory when done
|
132 |
+
@contextlib.contextmanager
|
133 |
+
def remove_output(*sources):
|
134 |
+
try:
|
135 |
+
yield
|
136 |
+
finally:
|
137 |
+
for src in sources:
|
138 |
+
shutil.rmtree(src)
|
139 |
+
|
140 |
+
|
141 |
+
with remove_output("pybind11/include", "pybind11/share"):
|
142 |
+
# Generate the files if they are not present.
|
143 |
+
with TemporaryDirectory() as tmpdir:
|
144 |
+
cmd = ["cmake", "-S", ".", "-B", tmpdir] + [
|
145 |
+
"-DCMAKE_INSTALL_PREFIX=pybind11",
|
146 |
+
"-DBUILD_TESTING=OFF",
|
147 |
+
"-DPYBIND11_NOPYTHON=ON",
|
148 |
+
]
|
149 |
+
cmake_opts = dict(cwd=DIR, stdout=sys.stdout, stderr=sys.stderr)
|
150 |
+
subprocess.check_call(cmd, **cmake_opts)
|
151 |
+
subprocess.check_call(["cmake", "--install", tmpdir], **cmake_opts)
|
152 |
+
|
153 |
+
txt = get_and_replace(setup_py, version=version, extra_cmd=extra_cmd)
|
154 |
+
code = compile(txt, setup_py, "exec")
|
155 |
+
exec(code, {"SDist": SDist})
|
third-party/DPVO/Pangolin/components/pango_python/pybind11/tests/CMakeLists.txt
ADDED
@@ -0,0 +1,495 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# CMakeLists.txt -- Build system for the pybind11 test suite
|
2 |
+
#
|
3 |
+
# Copyright (c) 2015 Wenzel Jakob <[email protected]>
|
4 |
+
#
|
5 |
+
# All rights reserved. Use of this source code is governed by a
|
6 |
+
# BSD-style license that can be found in the LICENSE file.
|
7 |
+
|
8 |
+
cmake_minimum_required(VERSION 3.4)
|
9 |
+
|
10 |
+
# The `cmake_minimum_required(VERSION 3.4...3.18)` syntax does not work with
|
11 |
+
# some versions of VS that have a patched CMake 3.11. This forces us to emulate
|
12 |
+
# the behavior using the following workaround:
|
13 |
+
if(${CMAKE_VERSION} VERSION_LESS 3.18)
|
14 |
+
cmake_policy(VERSION ${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION})
|
15 |
+
else()
|
16 |
+
cmake_policy(VERSION 3.18)
|
17 |
+
endif()
|
18 |
+
|
19 |
+
# Only needed for CMake < 3.5 support
|
20 |
+
include(CMakeParseArguments)
|
21 |
+
|
22 |
+
# Filter out items; print an optional message if any items filtered
|
23 |
+
#
|
24 |
+
# Usage:
|
25 |
+
# pybind11_filter_tests(LISTNAME file1.cpp file2.cpp ... MESSAGE "")
|
26 |
+
#
|
27 |
+
macro(pybind11_filter_tests LISTNAME)
|
28 |
+
cmake_parse_arguments(ARG "" "MESSAGE" "" ${ARGN})
|
29 |
+
set(PYBIND11_FILTER_TESTS_FOUND OFF)
|
30 |
+
foreach(filename IN LISTS ARG_UNPARSED_ARGUMENTS)
|
31 |
+
list(FIND ${LISTNAME} ${filename} _FILE_FOUND)
|
32 |
+
if(_FILE_FOUND GREATER -1)
|
33 |
+
list(REMOVE_AT ${LISTNAME} ${_FILE_FOUND})
|
34 |
+
set(PYBIND11_FILTER_TESTS_FOUND ON)
|
35 |
+
endif()
|
36 |
+
endforeach()
|
37 |
+
if(PYBIND11_FILTER_TESTS_FOUND AND ARG_MESSAGE)
|
38 |
+
message(STATUS "${ARG_MESSAGE}")
|
39 |
+
endif()
|
40 |
+
endmacro()
|
41 |
+
|
42 |
+
macro(possibly_uninitialized)
|
43 |
+
foreach(VARNAME ${ARGN})
|
44 |
+
if(NOT DEFINED "${VARNAME}")
|
45 |
+
set("${VARNAME}" "")
|
46 |
+
endif()
|
47 |
+
endforeach()
|
48 |
+
endmacro()
|
49 |
+
|
50 |
+
# New Python support
|
51 |
+
if(DEFINED Python_EXECUTABLE)
|
52 |
+
set(PYTHON_EXECUTABLE "${Python_EXECUTABLE}")
|
53 |
+
set(PYTHON_VERSION "${Python_VERSION}")
|
54 |
+
endif()
|
55 |
+
|
56 |
+
# There's no harm in including a project in a project
|
57 |
+
project(pybind11_tests CXX)
|
58 |
+
|
59 |
+
# Access FindCatch and more
|
60 |
+
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/../tools")
|
61 |
+
|
62 |
+
option(PYBIND11_WERROR "Report all warnings as errors" OFF)
|
63 |
+
option(DOWNLOAD_EIGEN "Download EIGEN (requires CMake 3.11+)" OFF)
|
64 |
+
option(PYBIND11_CUDA_TESTS "Enable building CUDA tests (requires CMake 3.12+)" OFF)
|
65 |
+
set(PYBIND11_TEST_OVERRIDE
|
66 |
+
""
|
67 |
+
CACHE STRING "Tests from ;-separated list of *.cpp files will be built instead of all tests")
|
68 |
+
set(PYBIND11_TEST_FILTER
|
69 |
+
""
|
70 |
+
CACHE STRING "Tests from ;-separated list of *.cpp files will be removed from all tests")
|
71 |
+
|
72 |
+
if(CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_SOURCE_DIR)
|
73 |
+
# We're being loaded directly, i.e. not via add_subdirectory, so make this
|
74 |
+
# work as its own project and load the pybind11Config to get the tools we need
|
75 |
+
find_package(pybind11 REQUIRED CONFIG)
|
76 |
+
endif()
|
77 |
+
|
78 |
+
if(NOT CMAKE_BUILD_TYPE AND NOT DEFINED CMAKE_CONFIGURATION_TYPES)
|
79 |
+
message(STATUS "Setting tests build type to MinSizeRel as none was specified")
|
80 |
+
set(CMAKE_BUILD_TYPE
|
81 |
+
MinSizeRel
|
82 |
+
CACHE STRING "Choose the type of build." FORCE)
|
83 |
+
set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS "Debug" "Release" "MinSizeRel"
|
84 |
+
"RelWithDebInfo")
|
85 |
+
endif()
|
86 |
+
|
87 |
+
if(PYBIND11_CUDA_TESTS)
|
88 |
+
enable_language(CUDA)
|
89 |
+
if(DEFINED CMAKE_CXX_STANDARD)
|
90 |
+
set(CMAKE_CUDA_STANDARD ${CMAKE_CXX_STANDARD})
|
91 |
+
endif()
|
92 |
+
set(CMAKE_CUDA_STANDARD_REQUIRED ON)
|
93 |
+
endif()
|
94 |
+
|
95 |
+
# Full set of test files (you can override these; see below)
|
96 |
+
set(PYBIND11_TEST_FILES
|
97 |
+
test_async.cpp
|
98 |
+
test_buffers.cpp
|
99 |
+
test_builtin_casters.cpp
|
100 |
+
test_call_policies.cpp
|
101 |
+
test_callbacks.cpp
|
102 |
+
test_chrono.cpp
|
103 |
+
test_class.cpp
|
104 |
+
test_constants_and_functions.cpp
|
105 |
+
test_copy_move.cpp
|
106 |
+
test_custom_type_casters.cpp
|
107 |
+
test_docstring_options.cpp
|
108 |
+
test_eigen.cpp
|
109 |
+
test_enum.cpp
|
110 |
+
test_eval.cpp
|
111 |
+
test_exceptions.cpp
|
112 |
+
test_factory_constructors.cpp
|
113 |
+
test_gil_scoped.cpp
|
114 |
+
test_iostream.cpp
|
115 |
+
test_kwargs_and_defaults.cpp
|
116 |
+
test_local_bindings.cpp
|
117 |
+
test_methods_and_attributes.cpp
|
118 |
+
test_modules.cpp
|
119 |
+
test_multiple_inheritance.cpp
|
120 |
+
test_numpy_array.cpp
|
121 |
+
test_numpy_dtypes.cpp
|
122 |
+
test_numpy_vectorize.cpp
|
123 |
+
test_opaque_types.cpp
|
124 |
+
test_operator_overloading.cpp
|
125 |
+
test_pickling.cpp
|
126 |
+
test_pytypes.cpp
|
127 |
+
test_sequences_and_iterators.cpp
|
128 |
+
test_smart_ptr.cpp
|
129 |
+
test_stl.cpp
|
130 |
+
test_stl_binders.cpp
|
131 |
+
test_tagbased_polymorphic.cpp
|
132 |
+
test_union.cpp
|
133 |
+
test_virtual_functions.cpp)
|
134 |
+
|
135 |
+
# Invoking cmake with something like:
|
136 |
+
# cmake -DPYBIND11_TEST_OVERRIDE="test_callbacks.cpp;test_pickling.cpp" ..
|
137 |
+
# lets you override the tests that get compiled and run. You can restore to all tests with:
|
138 |
+
# cmake -DPYBIND11_TEST_OVERRIDE= ..
|
139 |
+
if(PYBIND11_TEST_OVERRIDE)
|
140 |
+
set(PYBIND11_TEST_FILES ${PYBIND11_TEST_OVERRIDE})
|
141 |
+
endif()
|
142 |
+
|
143 |
+
# You can also filter tests:
|
144 |
+
if(PYBIND11_TEST_FILTER)
|
145 |
+
pybind11_filter_tests(PYBIND11_TEST_FILES ${PYBIND11_TEST_FILTER})
|
146 |
+
endif()
|
147 |
+
|
148 |
+
if(PYTHON_VERSION VERSION_LESS 3.5)
|
149 |
+
pybind11_filter_tests(PYBIND11_TEST_FILES test_async.cpp MESSAGE
|
150 |
+
"Skipping test_async on Python 2")
|
151 |
+
endif()
|
152 |
+
|
153 |
+
# Skip tests for CUDA check:
|
154 |
+
# /pybind11/tests/test_constants_and_functions.cpp(125):
|
155 |
+
# error: incompatible exception specifications
|
156 |
+
if(PYBIND11_CUDA_TESTS)
|
157 |
+
pybind11_filter_tests(
|
158 |
+
PYBIND11_TEST_FILES test_constants_and_functions.cpp MESSAGE
|
159 |
+
"Skipping test_constants_and_functions due to incompatible exception specifications")
|
160 |
+
endif()
|
161 |
+
|
162 |
+
string(REPLACE ".cpp" ".py" PYBIND11_PYTEST_FILES "${PYBIND11_TEST_FILES}")
|
163 |
+
|
164 |
+
# Contains the set of test files that require pybind11_cross_module_tests to be
|
165 |
+
# built; if none of these are built (i.e. because TEST_OVERRIDE is used and
|
166 |
+
# doesn't include them) the second module doesn't get built.
|
167 |
+
set(PYBIND11_CROSS_MODULE_TESTS test_exceptions.py test_local_bindings.py test_stl.py
|
168 |
+
test_stl_binders.py)
|
169 |
+
|
170 |
+
set(PYBIND11_CROSS_MODULE_GIL_TESTS test_gil_scoped.py)
|
171 |
+
|
172 |
+
# Check if Eigen is available; if not, remove from PYBIND11_TEST_FILES (but
|
173 |
+
# keep it in PYBIND11_PYTEST_FILES, so that we get the "eigen is not installed"
|
174 |
+
# skip message).
|
175 |
+
list(FIND PYBIND11_TEST_FILES test_eigen.cpp PYBIND11_TEST_FILES_EIGEN_I)
|
176 |
+
if(PYBIND11_TEST_FILES_EIGEN_I GREATER -1)
|
177 |
+
# Try loading via newer Eigen's Eigen3Config first (bypassing tools/FindEigen3.cmake).
|
178 |
+
# Eigen 3.3.1+ exports a cmake 3.0+ target for handling dependency requirements, but also
|
179 |
+
# produces a fatal error if loaded from a pre-3.0 cmake.
|
180 |
+
if(DOWNLOAD_EIGEN)
|
181 |
+
if(CMAKE_VERSION VERSION_LESS 3.11)
|
182 |
+
message(FATAL_ERROR "CMake 3.11+ required when using DOWNLOAD_EIGEN")
|
183 |
+
endif()
|
184 |
+
|
185 |
+
set(EIGEN3_VERSION_STRING "3.3.8")
|
186 |
+
|
187 |
+
include(FetchContent)
|
188 |
+
FetchContent_Declare(
|
189 |
+
eigen
|
190 |
+
GIT_REPOSITORY https://gitlab.com/libeigen/eigen.git
|
191 |
+
GIT_TAG ${EIGEN3_VERSION_STRING})
|
192 |
+
|
193 |
+
FetchContent_GetProperties(eigen)
|
194 |
+
if(NOT eigen_POPULATED)
|
195 |
+
message(STATUS "Downloading Eigen")
|
196 |
+
FetchContent_Populate(eigen)
|
197 |
+
endif()
|
198 |
+
|
199 |
+
set(EIGEN3_INCLUDE_DIR ${eigen_SOURCE_DIR})
|
200 |
+
set(EIGEN3_FOUND TRUE)
|
201 |
+
|
202 |
+
else()
|
203 |
+
find_package(Eigen3 3.2.7 QUIET CONFIG)
|
204 |
+
|
205 |
+
if(NOT EIGEN3_FOUND)
|
206 |
+
# Couldn't load via target, so fall back to allowing module mode finding, which will pick up
|
207 |
+
# tools/FindEigen3.cmake
|
208 |
+
find_package(Eigen3 3.2.7 QUIET)
|
209 |
+
endif()
|
210 |
+
endif()
|
211 |
+
|
212 |
+
if(EIGEN3_FOUND)
|
213 |
+
if(NOT TARGET Eigen3::Eigen)
|
214 |
+
add_library(Eigen3::Eigen IMPORTED INTERFACE)
|
215 |
+
set_property(TARGET Eigen3::Eigen PROPERTY INTERFACE_INCLUDE_DIRECTORIES
|
216 |
+
"${EIGEN3_INCLUDE_DIR}")
|
217 |
+
endif()
|
218 |
+
|
219 |
+
# Eigen 3.3.1+ cmake sets EIGEN3_VERSION_STRING (and hard codes the version when installed
|
220 |
+
# rather than looking it up in the cmake script); older versions, and the
|
221 |
+
# tools/FindEigen3.cmake, set EIGEN3_VERSION instead.
|
222 |
+
if(NOT EIGEN3_VERSION AND EIGEN3_VERSION_STRING)
|
223 |
+
set(EIGEN3_VERSION ${EIGEN3_VERSION_STRING})
|
224 |
+
endif()
|
225 |
+
message(STATUS "Building tests with Eigen v${EIGEN3_VERSION}")
|
226 |
+
else()
|
227 |
+
list(REMOVE_AT PYBIND11_TEST_FILES ${PYBIND11_TEST_FILES_EIGEN_I})
|
228 |
+
message(
|
229 |
+
STATUS "Building tests WITHOUT Eigen, use -DDOWNLOAD_EIGEN=ON on CMake 3.11+ to download")
|
230 |
+
endif()
|
231 |
+
endif()
|
232 |
+
|
233 |
+
# Optional dependency for some tests (boost::variant is only supported with version >= 1.56)
|
234 |
+
find_package(Boost 1.56)
|
235 |
+
|
236 |
+
if(Boost_FOUND)
|
237 |
+
if(NOT TARGET Boost::headers)
|
238 |
+
add_library(Boost::headers IMPORTED INTERFACE)
|
239 |
+
if(TARGET Boost::boost)
|
240 |
+
# Classic FindBoost
|
241 |
+
set_property(TARGET Boost::boost PROPERTY INTERFACE_LINK_LIBRARIES Boost::boost)
|
242 |
+
else()
|
243 |
+
# Very old FindBoost, or newer Boost than CMake in older CMakes
|
244 |
+
set_property(TARGET Boost::headers PROPERTY INTERFACE_INCLUDE_DIRECTORIES
|
245 |
+
${Boost_INCLUDE_DIRS})
|
246 |
+
endif()
|
247 |
+
endif()
|
248 |
+
endif()
|
249 |
+
|
250 |
+
# Check if we need to add -lstdc++fs or -lc++fs or nothing
|
251 |
+
if(MSVC)
|
252 |
+
set(STD_FS_NO_LIB_NEEDED TRUE)
|
253 |
+
else()
|
254 |
+
file(
|
255 |
+
WRITE ${CMAKE_CURRENT_BINARY_DIR}/main.cpp
|
256 |
+
"#include <filesystem>\nint main(int argc, char ** argv) {\n std::filesystem::path p(argv[0]);\n return p.string().length();\n}"
|
257 |
+
)
|
258 |
+
try_compile(
|
259 |
+
STD_FS_NO_LIB_NEEDED ${CMAKE_CURRENT_BINARY_DIR}
|
260 |
+
SOURCES ${CMAKE_CURRENT_BINARY_DIR}/main.cpp
|
261 |
+
COMPILE_DEFINITIONS -std=c++17)
|
262 |
+
try_compile(
|
263 |
+
STD_FS_NEEDS_STDCXXFS ${CMAKE_CURRENT_BINARY_DIR}
|
264 |
+
SOURCES ${CMAKE_CURRENT_BINARY_DIR}/main.cpp
|
265 |
+
COMPILE_DEFINITIONS -std=c++17
|
266 |
+
LINK_LIBRARIES stdc++fs)
|
267 |
+
try_compile(
|
268 |
+
STD_FS_NEEDS_CXXFS ${CMAKE_CURRENT_BINARY_DIR}
|
269 |
+
SOURCES ${CMAKE_CURRENT_BINARY_DIR}/main.cpp
|
270 |
+
COMPILE_DEFINITIONS -std=c++17
|
271 |
+
LINK_LIBRARIES c++fs)
|
272 |
+
endif()
|
273 |
+
|
274 |
+
if(${STD_FS_NEEDS_STDCXXFS})
|
275 |
+
set(STD_FS_LIB stdc++fs)
|
276 |
+
elseif(${STD_FS_NEEDS_CXXFS})
|
277 |
+
set(STD_FS_LIB c++fs)
|
278 |
+
elseif(${STD_FS_NO_LIB_NEEDED})
|
279 |
+
set(STD_FS_LIB "")
|
280 |
+
else()
|
281 |
+
message(WARNING "Unknown compiler - not passing -lstdc++fs")
|
282 |
+
set(STD_FS_LIB "")
|
283 |
+
endif()
|
284 |
+
|
285 |
+
# Compile with compiler warnings turned on
|
286 |
+
function(pybind11_enable_warnings target_name)
|
287 |
+
if(MSVC)
|
288 |
+
target_compile_options(${target_name} PRIVATE /W4)
|
289 |
+
elseif(CMAKE_CXX_COMPILER_ID MATCHES "(GNU|Intel|Clang)" AND NOT PYBIND11_CUDA_TESTS)
|
290 |
+
target_compile_options(
|
291 |
+
${target_name}
|
292 |
+
PRIVATE -Wall
|
293 |
+
-Wextra
|
294 |
+
-Wconversion
|
295 |
+
-Wcast-qual
|
296 |
+
-Wdeprecated
|
297 |
+
-Wundef
|
298 |
+
-Wnon-virtual-dtor)
|
299 |
+
endif()
|
300 |
+
|
301 |
+
if(PYBIND11_WERROR)
|
302 |
+
if(MSVC)
|
303 |
+
target_compile_options(${target_name} PRIVATE /WX)
|
304 |
+
elseif(PYBIND11_CUDA_TESTS)
|
305 |
+
target_compile_options(${target_name} PRIVATE "SHELL:-Werror all-warnings")
|
306 |
+
elseif(CMAKE_CXX_COMPILER_ID MATCHES "(GNU|Clang|IntelLLVM)")
|
307 |
+
target_compile_options(${target_name} PRIVATE -Werror)
|
308 |
+
elseif(CMAKE_CXX_COMPILER_ID STREQUAL "Intel")
|
309 |
+
target_compile_options(
|
310 |
+
${target_name}
|
311 |
+
PRIVATE
|
312 |
+
-Werror-all
|
313 |
+
# "Inlining inhibited by limit max-size", "Inlining inhibited by limit max-total-size"
|
314 |
+
-diag-disable 11074,11076)
|
315 |
+
endif()
|
316 |
+
endif()
|
317 |
+
|
318 |
+
# Needs to be re-added since the ordering requires these to be after the ones above
|
319 |
+
if(CMAKE_CXX_STANDARD
|
320 |
+
AND CMAKE_CXX_COMPILER_ID MATCHES "Clang"
|
321 |
+
AND PYTHON_VERSION VERSION_LESS 3.0)
|
322 |
+
if(CMAKE_CXX_STANDARD LESS 17)
|
323 |
+
target_compile_options(${target_name} PUBLIC -Wno-deprecated-register)
|
324 |
+
else()
|
325 |
+
target_compile_options(${target_name} PUBLIC -Wno-register)
|
326 |
+
endif()
|
327 |
+
endif()
|
328 |
+
endfunction()
|
329 |
+
|
330 |
+
set(test_targets pybind11_tests)
|
331 |
+
|
332 |
+
# Build pybind11_cross_module_tests if any test_whatever.py are being built that require it
|
333 |
+
foreach(t ${PYBIND11_CROSS_MODULE_TESTS})
|
334 |
+
list(FIND PYBIND11_PYTEST_FILES ${t} i)
|
335 |
+
if(i GREATER -1)
|
336 |
+
list(APPEND test_targets pybind11_cross_module_tests)
|
337 |
+
break()
|
338 |
+
endif()
|
339 |
+
endforeach()
|
340 |
+
|
341 |
+
foreach(t ${PYBIND11_CROSS_MODULE_GIL_TESTS})
|
342 |
+
list(FIND PYBIND11_PYTEST_FILES ${t} i)
|
343 |
+
if(i GREATER -1)
|
344 |
+
list(APPEND test_targets cross_module_gil_utils)
|
345 |
+
break()
|
346 |
+
endif()
|
347 |
+
endforeach()
|
348 |
+
|
349 |
+
# Support CUDA testing by forcing the target file to compile with NVCC
|
350 |
+
if(PYBIND11_CUDA_TESTS)
|
351 |
+
set_property(SOURCE ${PYBIND11_TEST_FILES} PROPERTY LANGUAGE CUDA)
|
352 |
+
endif()
|
353 |
+
|
354 |
+
foreach(target ${test_targets})
|
355 |
+
set(test_files ${PYBIND11_TEST_FILES})
|
356 |
+
if(NOT "${target}" STREQUAL "pybind11_tests")
|
357 |
+
set(test_files "")
|
358 |
+
endif()
|
359 |
+
|
360 |
+
# Support CUDA testing by forcing the target file to compile with NVCC
|
361 |
+
if(PYBIND11_CUDA_TESTS)
|
362 |
+
set_property(SOURCE ${target}.cpp PROPERTY LANGUAGE CUDA)
|
363 |
+
endif()
|
364 |
+
|
365 |
+
# Create the binding library
|
366 |
+
pybind11_add_module(${target} THIN_LTO ${target}.cpp ${test_files} ${PYBIND11_HEADERS})
|
367 |
+
pybind11_enable_warnings(${target})
|
368 |
+
|
369 |
+
if(NOT CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_CURRENT_BINARY_DIR)
|
370 |
+
get_property(
|
371 |
+
suffix
|
372 |
+
TARGET ${target}
|
373 |
+
PROPERTY SUFFIX)
|
374 |
+
set(source_output "${CMAKE_CURRENT_SOURCE_DIR}/${target}${suffix}")
|
375 |
+
if(suffix AND EXISTS "${source_output}")
|
376 |
+
message(WARNING "Output file also in source directory; "
|
377 |
+
"please remove to avoid confusion: ${source_output}")
|
378 |
+
endif()
|
379 |
+
endif()
|
380 |
+
|
381 |
+
if(MSVC)
|
382 |
+
target_compile_options(${target} PRIVATE /utf-8)
|
383 |
+
endif()
|
384 |
+
|
385 |
+
if(EIGEN3_FOUND)
|
386 |
+
target_link_libraries(${target} PRIVATE Eigen3::Eigen)
|
387 |
+
target_compile_definitions(${target} PRIVATE -DPYBIND11_TEST_EIGEN)
|
388 |
+
endif()
|
389 |
+
|
390 |
+
if(Boost_FOUND)
|
391 |
+
target_link_libraries(${target} PRIVATE Boost::headers)
|
392 |
+
target_compile_definitions(${target} PRIVATE -DPYBIND11_TEST_BOOST)
|
393 |
+
endif()
|
394 |
+
|
395 |
+
target_link_libraries(${target} PRIVATE ${STD_FS_LIB})
|
396 |
+
|
397 |
+
# Always write the output file directly into the 'tests' directory (even on MSVC)
|
398 |
+
if(NOT CMAKE_LIBRARY_OUTPUT_DIRECTORY)
|
399 |
+
set_target_properties(${target} PROPERTIES LIBRARY_OUTPUT_DIRECTORY
|
400 |
+
"${CMAKE_CURRENT_BINARY_DIR}")
|
401 |
+
|
402 |
+
if(DEFINED CMAKE_CONFIGURATION_TYPES)
|
403 |
+
foreach(config ${CMAKE_CONFIGURATION_TYPES})
|
404 |
+
string(TOUPPER ${config} config)
|
405 |
+
set_target_properties(${target} PROPERTIES LIBRARY_OUTPUT_DIRECTORY_${config}
|
406 |
+
"${CMAKE_CURRENT_BINARY_DIR}")
|
407 |
+
endforeach()
|
408 |
+
endif()
|
409 |
+
endif()
|
410 |
+
endforeach()
|
411 |
+
|
412 |
+
# Make sure pytest is found or produce a warning
|
413 |
+
pybind11_find_import(pytest VERSION 3.1)
|
414 |
+
|
415 |
+
if(NOT CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_CURRENT_BINARY_DIR)
|
416 |
+
# This is not used later in the build, so it's okay to regenerate each time.
|
417 |
+
configure_file("${CMAKE_CURRENT_SOURCE_DIR}/pytest.ini" "${CMAKE_CURRENT_BINARY_DIR}/pytest.ini"
|
418 |
+
COPYONLY)
|
419 |
+
file(APPEND "${CMAKE_CURRENT_BINARY_DIR}/pytest.ini"
|
420 |
+
"\ntestpaths = \"${CMAKE_CURRENT_SOURCE_DIR}\"")
|
421 |
+
|
422 |
+
endif()
|
423 |
+
|
424 |
+
# cmake 3.12 added list(transform <list> prepend
|
425 |
+
# but we can't use it yet
|
426 |
+
string(REPLACE "test_" "${CMAKE_CURRENT_SOURCE_DIR}/test_" PYBIND11_ABS_PYTEST_FILES
|
427 |
+
"${PYBIND11_PYTEST_FILES}")
|
428 |
+
|
429 |
+
set(PYBIND11_TEST_PREFIX_COMMAND
|
430 |
+
""
|
431 |
+
CACHE STRING "Put this before pytest, use for checkers and such")
|
432 |
+
|
433 |
+
# A single command to compile and run the tests
|
434 |
+
add_custom_target(
|
435 |
+
pytest
|
436 |
+
COMMAND ${PYBIND11_TEST_PREFIX_COMMAND} ${PYTHON_EXECUTABLE} -m pytest
|
437 |
+
${PYBIND11_ABS_PYTEST_FILES}
|
438 |
+
DEPENDS ${test_targets}
|
439 |
+
WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}"
|
440 |
+
USES_TERMINAL)
|
441 |
+
|
442 |
+
if(PYBIND11_TEST_OVERRIDE)
|
443 |
+
add_custom_command(
|
444 |
+
TARGET pytest
|
445 |
+
POST_BUILD
|
446 |
+
COMMAND ${CMAKE_COMMAND} -E echo
|
447 |
+
"Note: not all tests run: -DPYBIND11_TEST_OVERRIDE is in effect")
|
448 |
+
endif()
|
449 |
+
|
450 |
+
# cmake-format: off
|
451 |
+
add_custom_target(
|
452 |
+
memcheck
|
453 |
+
COMMAND
|
454 |
+
PYTHONMALLOC=malloc
|
455 |
+
valgrind
|
456 |
+
--leak-check=full
|
457 |
+
--show-leak-kinds=definite,indirect
|
458 |
+
--errors-for-leak-kinds=definite,indirect
|
459 |
+
--error-exitcode=1
|
460 |
+
--read-var-info=yes
|
461 |
+
--track-origins=yes
|
462 |
+
--suppressions="${CMAKE_CURRENT_SOURCE_DIR}/valgrind-python.supp"
|
463 |
+
--suppressions="${CMAKE_CURRENT_SOURCE_DIR}/valgrind-numpy-scipy.supp"
|
464 |
+
--gen-suppressions=all
|
465 |
+
${PYTHON_EXECUTABLE} -m pytest ${PYBIND11_ABS_PYTEST_FILES}
|
466 |
+
DEPENDS ${test_targets}
|
467 |
+
WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}"
|
468 |
+
USES_TERMINAL)
|
469 |
+
# cmake-format: on
|
470 |
+
|
471 |
+
# Add a check target to run all the tests, starting with pytest (we add dependencies to this below)
|
472 |
+
add_custom_target(check DEPENDS pytest)
|
473 |
+
|
474 |
+
# The remaining tests only apply when being built as part of the pybind11 project, but not if the
|
475 |
+
# tests are being built independently.
|
476 |
+
if(CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_SOURCE_DIR)
|
477 |
+
return()
|
478 |
+
endif()
|
479 |
+
|
480 |
+
# Add a post-build comment to show the primary test suite .so size and, if a previous size, compare it:
|
481 |
+
add_custom_command(
|
482 |
+
TARGET pybind11_tests
|
483 |
+
POST_BUILD
|
484 |
+
COMMAND
|
485 |
+
${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/../tools/libsize.py
|
486 |
+
$<TARGET_FILE:pybind11_tests>
|
487 |
+
${CMAKE_CURRENT_BINARY_DIR}/sosize-$<TARGET_FILE_NAME:pybind11_tests>.txt)
|
488 |
+
|
489 |
+
if(NOT PYBIND11_CUDA_TESTS)
|
490 |
+
# Test embedding the interpreter. Provides the `cpptest` target.
|
491 |
+
add_subdirectory(test_embed)
|
492 |
+
|
493 |
+
# Test CMake build using functions and targets from subdirectory or installed location
|
494 |
+
add_subdirectory(test_cmake_build)
|
495 |
+
endif()
|
third-party/DPVO/Pangolin/components/pango_python/pybind11/tests/conftest.py
ADDED
@@ -0,0 +1,208 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# -*- coding: utf-8 -*-
|
2 |
+
"""pytest configuration
|
3 |
+
|
4 |
+
Extends output capture as needed by pybind11: ignore constructors, optional unordered lines.
|
5 |
+
Adds docstring and exceptions message sanitizers: ignore Python 2 vs 3 differences.
|
6 |
+
"""
|
7 |
+
|
8 |
+
import contextlib
|
9 |
+
import difflib
|
10 |
+
import gc
|
11 |
+
import re
|
12 |
+
import textwrap
|
13 |
+
|
14 |
+
import pytest
|
15 |
+
|
16 |
+
import env
|
17 |
+
|
18 |
+
# Early diagnostic for failed imports
|
19 |
+
import pybind11_tests # noqa: F401
|
20 |
+
|
21 |
+
_unicode_marker = re.compile(r"u(\'[^\']*\')")
|
22 |
+
_long_marker = re.compile(r"([0-9])L")
|
23 |
+
_hexadecimal = re.compile(r"0x[0-9a-fA-F]+")
|
24 |
+
|
25 |
+
# Avoid collecting Python3 only files
|
26 |
+
collect_ignore = []
|
27 |
+
if env.PY2:
|
28 |
+
collect_ignore.append("test_async.py")
|
29 |
+
|
30 |
+
|
31 |
+
def _strip_and_dedent(s):
|
32 |
+
"""For triple-quote strings"""
|
33 |
+
return textwrap.dedent(s.lstrip("\n").rstrip())
|
34 |
+
|
35 |
+
|
36 |
+
def _split_and_sort(s):
|
37 |
+
"""For output which does not require specific line order"""
|
38 |
+
return sorted(_strip_and_dedent(s).splitlines())
|
39 |
+
|
40 |
+
|
41 |
+
def _make_explanation(a, b):
|
42 |
+
"""Explanation for a failed assert -- the a and b arguments are List[str]"""
|
43 |
+
return ["--- actual / +++ expected"] + [
|
44 |
+
line.strip("\n") for line in difflib.ndiff(a, b)
|
45 |
+
]
|
46 |
+
|
47 |
+
|
48 |
+
class Output(object):
|
49 |
+
"""Basic output post-processing and comparison"""
|
50 |
+
|
51 |
+
def __init__(self, string):
|
52 |
+
self.string = string
|
53 |
+
self.explanation = []
|
54 |
+
|
55 |
+
def __str__(self):
|
56 |
+
return self.string
|
57 |
+
|
58 |
+
def __eq__(self, other):
|
59 |
+
# Ignore constructor/destructor output which is prefixed with "###"
|
60 |
+
a = [
|
61 |
+
line
|
62 |
+
for line in self.string.strip().splitlines()
|
63 |
+
if not line.startswith("###")
|
64 |
+
]
|
65 |
+
b = _strip_and_dedent(other).splitlines()
|
66 |
+
if a == b:
|
67 |
+
return True
|
68 |
+
else:
|
69 |
+
self.explanation = _make_explanation(a, b)
|
70 |
+
return False
|
71 |
+
|
72 |
+
|
73 |
+
class Unordered(Output):
|
74 |
+
"""Custom comparison for output without strict line ordering"""
|
75 |
+
|
76 |
+
def __eq__(self, other):
|
77 |
+
a = _split_and_sort(self.string)
|
78 |
+
b = _split_and_sort(other)
|
79 |
+
if a == b:
|
80 |
+
return True
|
81 |
+
else:
|
82 |
+
self.explanation = _make_explanation(a, b)
|
83 |
+
return False
|
84 |
+
|
85 |
+
|
86 |
+
class Capture(object):
|
87 |
+
def __init__(self, capfd):
|
88 |
+
self.capfd = capfd
|
89 |
+
self.out = ""
|
90 |
+
self.err = ""
|
91 |
+
|
92 |
+
def __enter__(self):
|
93 |
+
self.capfd.readouterr()
|
94 |
+
return self
|
95 |
+
|
96 |
+
def __exit__(self, *args):
|
97 |
+
self.out, self.err = self.capfd.readouterr()
|
98 |
+
|
99 |
+
def __eq__(self, other):
|
100 |
+
a = Output(self.out)
|
101 |
+
b = other
|
102 |
+
if a == b:
|
103 |
+
return True
|
104 |
+
else:
|
105 |
+
self.explanation = a.explanation
|
106 |
+
return False
|
107 |
+
|
108 |
+
def __str__(self):
|
109 |
+
return self.out
|
110 |
+
|
111 |
+
def __contains__(self, item):
|
112 |
+
return item in self.out
|
113 |
+
|
114 |
+
@property
|
115 |
+
def unordered(self):
|
116 |
+
return Unordered(self.out)
|
117 |
+
|
118 |
+
@property
|
119 |
+
def stderr(self):
|
120 |
+
return Output(self.err)
|
121 |
+
|
122 |
+
|
123 |
+
@pytest.fixture
|
124 |
+
def capture(capsys):
|
125 |
+
"""Extended `capsys` with context manager and custom equality operators"""
|
126 |
+
return Capture(capsys)
|
127 |
+
|
128 |
+
|
129 |
+
class SanitizedString(object):
|
130 |
+
def __init__(self, sanitizer):
|
131 |
+
self.sanitizer = sanitizer
|
132 |
+
self.string = ""
|
133 |
+
self.explanation = []
|
134 |
+
|
135 |
+
def __call__(self, thing):
|
136 |
+
self.string = self.sanitizer(thing)
|
137 |
+
return self
|
138 |
+
|
139 |
+
def __eq__(self, other):
|
140 |
+
a = self.string
|
141 |
+
b = _strip_and_dedent(other)
|
142 |
+
if a == b:
|
143 |
+
return True
|
144 |
+
else:
|
145 |
+
self.explanation = _make_explanation(a.splitlines(), b.splitlines())
|
146 |
+
return False
|
147 |
+
|
148 |
+
|
149 |
+
def _sanitize_general(s):
|
150 |
+
s = s.strip()
|
151 |
+
s = s.replace("pybind11_tests.", "m.")
|
152 |
+
s = s.replace("unicode", "str")
|
153 |
+
s = _long_marker.sub(r"\1", s)
|
154 |
+
s = _unicode_marker.sub(r"\1", s)
|
155 |
+
return s
|
156 |
+
|
157 |
+
|
158 |
+
def _sanitize_docstring(thing):
|
159 |
+
s = thing.__doc__
|
160 |
+
s = _sanitize_general(s)
|
161 |
+
return s
|
162 |
+
|
163 |
+
|
164 |
+
@pytest.fixture
|
165 |
+
def doc():
|
166 |
+
"""Sanitize docstrings and add custom failure explanation"""
|
167 |
+
return SanitizedString(_sanitize_docstring)
|
168 |
+
|
169 |
+
|
170 |
+
def _sanitize_message(thing):
|
171 |
+
s = str(thing)
|
172 |
+
s = _sanitize_general(s)
|
173 |
+
s = _hexadecimal.sub("0", s)
|
174 |
+
return s
|
175 |
+
|
176 |
+
|
177 |
+
@pytest.fixture
|
178 |
+
def msg():
|
179 |
+
"""Sanitize messages and add custom failure explanation"""
|
180 |
+
return SanitizedString(_sanitize_message)
|
181 |
+
|
182 |
+
|
183 |
+
# noinspection PyUnusedLocal
|
184 |
+
def pytest_assertrepr_compare(op, left, right):
|
185 |
+
"""Hook to insert custom failure explanation"""
|
186 |
+
if hasattr(left, "explanation"):
|
187 |
+
return left.explanation
|
188 |
+
|
189 |
+
|
190 |
+
@contextlib.contextmanager
|
191 |
+
def suppress(exception):
|
192 |
+
"""Suppress the desired exception"""
|
193 |
+
try:
|
194 |
+
yield
|
195 |
+
except exception:
|
196 |
+
pass
|
197 |
+
|
198 |
+
|
199 |
+
def gc_collect():
|
200 |
+
"""Run the garbage collector twice (needed when running
|
201 |
+
reference counting tests with PyPy)"""
|
202 |
+
gc.collect()
|
203 |
+
gc.collect()
|
204 |
+
|
205 |
+
|
206 |
+
def pytest_configure():
|
207 |
+
pytest.suppress = suppress
|
208 |
+
pytest.gc_collect = gc_collect
|
third-party/DPVO/Pangolin/components/pango_python/pybind11/tests/constructor_stats.h
ADDED
@@ -0,0 +1,275 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
#pragma once
|
2 |
+
/*
|
3 |
+
tests/constructor_stats.h -- framework for printing and tracking object
|
4 |
+
instance lifetimes in example/test code.
|
5 |
+
|
6 |
+
Copyright (c) 2016 Jason Rhinelander <[email protected]>
|
7 |
+
|
8 |
+
All rights reserved. Use of this source code is governed by a
|
9 |
+
BSD-style license that can be found in the LICENSE file.
|
10 |
+
|
11 |
+
This header provides a few useful tools for writing examples or tests that want to check and/or
|
12 |
+
display object instance lifetimes. It requires that you include this header and add the following
|
13 |
+
function calls to constructors:
|
14 |
+
|
15 |
+
class MyClass {
|
16 |
+
MyClass() { ...; print_default_created(this); }
|
17 |
+
~MyClass() { ...; print_destroyed(this); }
|
18 |
+
MyClass(const MyClass &c) { ...; print_copy_created(this); }
|
19 |
+
MyClass(MyClass &&c) { ...; print_move_created(this); }
|
20 |
+
MyClass(int a, int b) { ...; print_created(this, a, b); }
|
21 |
+
MyClass &operator=(const MyClass &c) { ...; print_copy_assigned(this); }
|
22 |
+
MyClass &operator=(MyClass &&c) { ...; print_move_assigned(this); }
|
23 |
+
|
24 |
+
...
|
25 |
+
}
|
26 |
+
|
27 |
+
You can find various examples of these in several of the existing testing .cpp files. (Of course
|
28 |
+
you don't need to add any of the above constructors/operators that you don't actually have, except
|
29 |
+
for the destructor).
|
30 |
+
|
31 |
+
Each of these will print an appropriate message such as:
|
32 |
+
|
33 |
+
### MyClass @ 0x2801910 created via default constructor
|
34 |
+
### MyClass @ 0x27fa780 created 100 200
|
35 |
+
### MyClass @ 0x2801910 destroyed
|
36 |
+
### MyClass @ 0x27fa780 destroyed
|
37 |
+
|
38 |
+
You can also include extra arguments (such as the 100, 200 in the output above, coming from the
|
39 |
+
value constructor) for all of the above methods which will be included in the output.
|
40 |
+
|
41 |
+
For testing, each of these also keeps track the created instances and allows you to check how many
|
42 |
+
of the various constructors have been invoked from the Python side via code such as:
|
43 |
+
|
44 |
+
from pybind11_tests import ConstructorStats
|
45 |
+
cstats = ConstructorStats.get(MyClass)
|
46 |
+
print(cstats.alive())
|
47 |
+
print(cstats.default_constructions)
|
48 |
+
|
49 |
+
Note that `.alive()` should usually be the first thing you call as it invokes Python's garbage
|
50 |
+
collector to actually destroy objects that aren't yet referenced.
|
51 |
+
|
52 |
+
For everything except copy and move constructors and destructors, any extra values given to the
|
53 |
+
print_...() function is stored in a class-specific values list which you can retrieve and inspect
|
54 |
+
from the ConstructorStats instance `.values()` method.
|
55 |
+
|
56 |
+
In some cases, when you need to track instances of a C++ class not registered with pybind11, you
|
57 |
+
need to add a function returning the ConstructorStats for the C++ class; this can be done with:
|
58 |
+
|
59 |
+
m.def("get_special_cstats", &ConstructorStats::get<SpecialClass>, py::return_value_policy::reference)
|
60 |
+
|
61 |
+
Finally, you can suppress the output messages, but keep the constructor tracking (for
|
62 |
+
inspection/testing in python) by using the functions with `print_` replaced with `track_` (e.g.
|
63 |
+
`track_copy_created(this)`).
|
64 |
+
|
65 |
+
*/
|
66 |
+
|
67 |
+
#include "pybind11_tests.h"
|
68 |
+
#include <unordered_map>
|
69 |
+
#include <list>
|
70 |
+
#include <typeindex>
|
71 |
+
#include <sstream>
|
72 |
+
|
73 |
+
class ConstructorStats {
|
74 |
+
protected:
|
75 |
+
std::unordered_map<void*, int> _instances; // Need a map rather than set because members can shared address with parents
|
76 |
+
std::list<std::string> _values; // Used to track values (e.g. of value constructors)
|
77 |
+
public:
|
78 |
+
int default_constructions = 0;
|
79 |
+
int copy_constructions = 0;
|
80 |
+
int move_constructions = 0;
|
81 |
+
int copy_assignments = 0;
|
82 |
+
int move_assignments = 0;
|
83 |
+
|
84 |
+
void copy_created(void *inst) {
|
85 |
+
created(inst);
|
86 |
+
copy_constructions++;
|
87 |
+
}
|
88 |
+
|
89 |
+
void move_created(void *inst) {
|
90 |
+
created(inst);
|
91 |
+
move_constructions++;
|
92 |
+
}
|
93 |
+
|
94 |
+
void default_created(void *inst) {
|
95 |
+
created(inst);
|
96 |
+
default_constructions++;
|
97 |
+
}
|
98 |
+
|
99 |
+
void created(void *inst) {
|
100 |
+
++_instances[inst];
|
101 |
+
}
|
102 |
+
|
103 |
+
void destroyed(void *inst) {
|
104 |
+
if (--_instances[inst] < 0)
|
105 |
+
throw std::runtime_error("cstats.destroyed() called with unknown "
|
106 |
+
"instance; potential double-destruction "
|
107 |
+
"or a missing cstats.created()");
|
108 |
+
}
|
109 |
+
|
110 |
+
static void gc() {
|
111 |
+
// Force garbage collection to ensure any pending destructors are invoked:
|
112 |
+
#if defined(PYPY_VERSION)
|
113 |
+
PyObject *globals = PyEval_GetGlobals();
|
114 |
+
PyObject *result = PyRun_String(
|
115 |
+
"import gc\n"
|
116 |
+
"for i in range(2):"
|
117 |
+
" gc.collect()\n",
|
118 |
+
Py_file_input, globals, globals);
|
119 |
+
if (result == nullptr)
|
120 |
+
throw py::error_already_set();
|
121 |
+
Py_DECREF(result);
|
122 |
+
#else
|
123 |
+
py::module_::import("gc").attr("collect")();
|
124 |
+
#endif
|
125 |
+
}
|
126 |
+
|
127 |
+
int alive() {
|
128 |
+
gc();
|
129 |
+
int total = 0;
|
130 |
+
for (const auto &p : _instances)
|
131 |
+
if (p.second > 0)
|
132 |
+
total += p.second;
|
133 |
+
return total;
|
134 |
+
}
|
135 |
+
|
136 |
+
void value() {} // Recursion terminator
|
137 |
+
// Takes one or more values, converts them to strings, then stores them.
|
138 |
+
template <typename T, typename... Tmore> void value(const T &v, Tmore &&...args) {
|
139 |
+
std::ostringstream oss;
|
140 |
+
oss << v;
|
141 |
+
_values.push_back(oss.str());
|
142 |
+
value(std::forward<Tmore>(args)...);
|
143 |
+
}
|
144 |
+
|
145 |
+
// Move out stored values
|
146 |
+
py::list values() {
|
147 |
+
py::list l;
|
148 |
+
for (const auto &v : _values) l.append(py::cast(v));
|
149 |
+
_values.clear();
|
150 |
+
return l;
|
151 |
+
}
|
152 |
+
|
153 |
+
// Gets constructor stats from a C++ type index
|
154 |
+
static ConstructorStats& get(std::type_index type) {
|
155 |
+
static std::unordered_map<std::type_index, ConstructorStats> all_cstats;
|
156 |
+
return all_cstats[type];
|
157 |
+
}
|
158 |
+
|
159 |
+
// Gets constructor stats from a C++ type
|
160 |
+
template <typename T> static ConstructorStats& get() {
|
161 |
+
#if defined(PYPY_VERSION)
|
162 |
+
gc();
|
163 |
+
#endif
|
164 |
+
return get(typeid(T));
|
165 |
+
}
|
166 |
+
|
167 |
+
// Gets constructor stats from a Python class
|
168 |
+
static ConstructorStats& get(py::object class_) {
|
169 |
+
auto &internals = py::detail::get_internals();
|
170 |
+
const std::type_index *t1 = nullptr, *t2 = nullptr;
|
171 |
+
try {
|
172 |
+
auto *type_info = internals.registered_types_py.at((PyTypeObject *) class_.ptr()).at(0);
|
173 |
+
for (auto &p : internals.registered_types_cpp) {
|
174 |
+
if (p.second == type_info) {
|
175 |
+
if (t1) {
|
176 |
+
t2 = &p.first;
|
177 |
+
break;
|
178 |
+
}
|
179 |
+
t1 = &p.first;
|
180 |
+
}
|
181 |
+
}
|
182 |
+
}
|
183 |
+
catch (const std::out_of_range&) {}
|
184 |
+
if (!t1) throw std::runtime_error("Unknown class passed to ConstructorStats::get()");
|
185 |
+
auto &cs1 = get(*t1);
|
186 |
+
// If we have both a t1 and t2 match, one is probably the trampoline class; return whichever
|
187 |
+
// has more constructions (typically one or the other will be 0)
|
188 |
+
if (t2) {
|
189 |
+
auto &cs2 = get(*t2);
|
190 |
+
int cs1_total = cs1.default_constructions + cs1.copy_constructions + cs1.move_constructions + (int) cs1._values.size();
|
191 |
+
int cs2_total = cs2.default_constructions + cs2.copy_constructions + cs2.move_constructions + (int) cs2._values.size();
|
192 |
+
if (cs2_total > cs1_total) return cs2;
|
193 |
+
}
|
194 |
+
return cs1;
|
195 |
+
}
|
196 |
+
};
|
197 |
+
|
198 |
+
// To track construction/destruction, you need to call these methods from the various
|
199 |
+
// constructors/operators. The ones that take extra values record the given values in the
|
200 |
+
// constructor stats values for later inspection.
|
201 |
+
template <class T> void track_copy_created(T *inst) { ConstructorStats::get<T>().copy_created(inst); }
|
202 |
+
template <class T> void track_move_created(T *inst) { ConstructorStats::get<T>().move_created(inst); }
|
203 |
+
template <class T, typename... Values> void track_copy_assigned(T *, Values &&...values) {
|
204 |
+
auto &cst = ConstructorStats::get<T>();
|
205 |
+
cst.copy_assignments++;
|
206 |
+
cst.value(std::forward<Values>(values)...);
|
207 |
+
}
|
208 |
+
template <class T, typename... Values> void track_move_assigned(T *, Values &&...values) {
|
209 |
+
auto &cst = ConstructorStats::get<T>();
|
210 |
+
cst.move_assignments++;
|
211 |
+
cst.value(std::forward<Values>(values)...);
|
212 |
+
}
|
213 |
+
template <class T, typename... Values> void track_default_created(T *inst, Values &&...values) {
|
214 |
+
auto &cst = ConstructorStats::get<T>();
|
215 |
+
cst.default_created(inst);
|
216 |
+
cst.value(std::forward<Values>(values)...);
|
217 |
+
}
|
218 |
+
template <class T, typename... Values> void track_created(T *inst, Values &&...values) {
|
219 |
+
auto &cst = ConstructorStats::get<T>();
|
220 |
+
cst.created(inst);
|
221 |
+
cst.value(std::forward<Values>(values)...);
|
222 |
+
}
|
223 |
+
template <class T, typename... Values> void track_destroyed(T *inst) {
|
224 |
+
ConstructorStats::get<T>().destroyed(inst);
|
225 |
+
}
|
226 |
+
template <class T, typename... Values> void track_values(T *, Values &&...values) {
|
227 |
+
ConstructorStats::get<T>().value(std::forward<Values>(values)...);
|
228 |
+
}
|
229 |
+
|
230 |
+
/// Don't cast pointers to Python, print them as strings
|
231 |
+
inline const char *format_ptrs(const char *p) { return p; }
|
232 |
+
template <typename T>
|
233 |
+
py::str format_ptrs(T *p) { return "{:#x}"_s.format(reinterpret_cast<std::uintptr_t>(p)); }
|
234 |
+
template <typename T>
|
235 |
+
auto format_ptrs(T &&x) -> decltype(std::forward<T>(x)) { return std::forward<T>(x); }
|
236 |
+
|
237 |
+
template <class T, typename... Output>
|
238 |
+
void print_constr_details(T *inst, const std::string &action, Output &&...output) {
|
239 |
+
py::print("###", py::type_id<T>(), "@", format_ptrs(inst), action,
|
240 |
+
format_ptrs(std::forward<Output>(output))...);
|
241 |
+
}
|
242 |
+
|
243 |
+
// Verbose versions of the above:
|
244 |
+
template <class T, typename... Values> void print_copy_created(T *inst, Values &&...values) { // NB: this prints, but doesn't store, given values
|
245 |
+
print_constr_details(inst, "created via copy constructor", values...);
|
246 |
+
track_copy_created(inst);
|
247 |
+
}
|
248 |
+
template <class T, typename... Values> void print_move_created(T *inst, Values &&...values) { // NB: this prints, but doesn't store, given values
|
249 |
+
print_constr_details(inst, "created via move constructor", values...);
|
250 |
+
track_move_created(inst);
|
251 |
+
}
|
252 |
+
template <class T, typename... Values> void print_copy_assigned(T *inst, Values &&...values) {
|
253 |
+
print_constr_details(inst, "assigned via copy assignment", values...);
|
254 |
+
track_copy_assigned(inst, values...);
|
255 |
+
}
|
256 |
+
template <class T, typename... Values> void print_move_assigned(T *inst, Values &&...values) {
|
257 |
+
print_constr_details(inst, "assigned via move assignment", values...);
|
258 |
+
track_move_assigned(inst, values...);
|
259 |
+
}
|
260 |
+
template <class T, typename... Values> void print_default_created(T *inst, Values &&...values) {
|
261 |
+
print_constr_details(inst, "created via default constructor", values...);
|
262 |
+
track_default_created(inst, values...);
|
263 |
+
}
|
264 |
+
template <class T, typename... Values> void print_created(T *inst, Values &&...values) {
|
265 |
+
print_constr_details(inst, "created", values...);
|
266 |
+
track_created(inst, values...);
|
267 |
+
}
|
268 |
+
template <class T, typename... Values> void print_destroyed(T *inst, Values &&...values) { // Prints but doesn't store given values
|
269 |
+
print_constr_details(inst, "destroyed", values...);
|
270 |
+
track_destroyed(inst);
|
271 |
+
}
|
272 |
+
template <class T, typename... Values> void print_values(T *inst, Values &&...values) {
|
273 |
+
print_constr_details(inst, ":", values...);
|
274 |
+
track_values(inst, values...);
|
275 |
+
}
|
third-party/DPVO/Pangolin/components/pango_python/pybind11/tests/cross_module_gil_utils.cpp
ADDED
@@ -0,0 +1,73 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/*
|
2 |
+
tests/cross_module_gil_utils.cpp -- tools for acquiring GIL from a different module
|
3 |
+
|
4 |
+
Copyright (c) 2019 Google LLC
|
5 |
+
|
6 |
+
All rights reserved. Use of this source code is governed by a
|
7 |
+
BSD-style license that can be found in the LICENSE file.
|
8 |
+
*/
|
9 |
+
#include <pybind11/pybind11.h>
|
10 |
+
#include <cstdint>
|
11 |
+
|
12 |
+
// This file mimics a DSO that makes pybind11 calls but does not define a
|
13 |
+
// PYBIND11_MODULE. The purpose is to test that such a DSO can create a
|
14 |
+
// py::gil_scoped_acquire when the running thread is in a GIL-released state.
|
15 |
+
//
|
16 |
+
// Note that we define a Python module here for convenience, but in general
|
17 |
+
// this need not be the case. The typical scenario would be a DSO that implements
|
18 |
+
// shared logic used internally by multiple pybind11 modules.
|
19 |
+
|
20 |
+
namespace {
|
21 |
+
|
22 |
+
namespace py = pybind11;
|
23 |
+
void gil_acquire() { py::gil_scoped_acquire gil; }
|
24 |
+
|
25 |
+
constexpr char kModuleName[] = "cross_module_gil_utils";
|
26 |
+
|
27 |
+
#if PY_MAJOR_VERSION >= 3
|
28 |
+
struct PyModuleDef moduledef = {
|
29 |
+
PyModuleDef_HEAD_INIT,
|
30 |
+
kModuleName,
|
31 |
+
NULL,
|
32 |
+
0,
|
33 |
+
NULL,
|
34 |
+
NULL,
|
35 |
+
NULL,
|
36 |
+
NULL,
|
37 |
+
NULL
|
38 |
+
};
|
39 |
+
#else
|
40 |
+
PyMethodDef module_methods[] = {
|
41 |
+
{NULL, NULL, 0, NULL}
|
42 |
+
};
|
43 |
+
#endif
|
44 |
+
|
45 |
+
} // namespace
|
46 |
+
|
47 |
+
extern "C" PYBIND11_EXPORT
|
48 |
+
#if PY_MAJOR_VERSION >= 3
|
49 |
+
PyObject* PyInit_cross_module_gil_utils()
|
50 |
+
#else
|
51 |
+
void initcross_module_gil_utils()
|
52 |
+
#endif
|
53 |
+
{
|
54 |
+
|
55 |
+
PyObject* m =
|
56 |
+
#if PY_MAJOR_VERSION >= 3
|
57 |
+
PyModule_Create(&moduledef);
|
58 |
+
#else
|
59 |
+
Py_InitModule(kModuleName, module_methods);
|
60 |
+
#endif
|
61 |
+
|
62 |
+
if (m != NULL) {
|
63 |
+
static_assert(
|
64 |
+
sizeof(&gil_acquire) == sizeof(void*),
|
65 |
+
"Function pointer must have the same size as void*");
|
66 |
+
PyModule_AddObject(m, "gil_acquire_funcaddr",
|
67 |
+
PyLong_FromVoidPtr(reinterpret_cast<void*>(&gil_acquire)));
|
68 |
+
}
|
69 |
+
|
70 |
+
#if PY_MAJOR_VERSION >= 3
|
71 |
+
return m;
|
72 |
+
#endif
|
73 |
+
}
|
third-party/DPVO/Pangolin/components/pango_python/pybind11/tests/env.py
ADDED
@@ -0,0 +1,33 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# -*- coding: utf-8 -*-
|
2 |
+
import platform
|
3 |
+
import sys
|
4 |
+
|
5 |
+
import pytest
|
6 |
+
|
7 |
+
LINUX = sys.platform.startswith("linux")
|
8 |
+
MACOS = sys.platform.startswith("darwin")
|
9 |
+
WIN = sys.platform.startswith("win32") or sys.platform.startswith("cygwin")
|
10 |
+
|
11 |
+
CPYTHON = platform.python_implementation() == "CPython"
|
12 |
+
PYPY = platform.python_implementation() == "PyPy"
|
13 |
+
|
14 |
+
PY2 = sys.version_info.major == 2
|
15 |
+
|
16 |
+
PY = sys.version_info
|
17 |
+
|
18 |
+
|
19 |
+
def deprecated_call():
|
20 |
+
"""
|
21 |
+
pytest.deprecated_call() seems broken in pytest<3.9.x; concretely, it
|
22 |
+
doesn't work on CPython 3.8.0 with pytest==3.3.2 on Ubuntu 18.04 (#2922).
|
23 |
+
|
24 |
+
This is a narrowed reimplementation of the following PR :(
|
25 |
+
https://github.com/pytest-dev/pytest/pull/4104
|
26 |
+
"""
|
27 |
+
# TODO: Remove this when testing requires pytest>=3.9.
|
28 |
+
pieces = pytest.__version__.split(".")
|
29 |
+
pytest_major_minor = (int(pieces[0]), int(pieces[1]))
|
30 |
+
if pytest_major_minor < (3, 9):
|
31 |
+
return pytest.warns((DeprecationWarning, PendingDeprecationWarning))
|
32 |
+
else:
|
33 |
+
return pytest.deprecated_call()
|
third-party/DPVO/Pangolin/components/pango_python/pybind11/tests/extra_python_package/pytest.ini
ADDED
File without changes
|
third-party/DPVO/Pangolin/components/pango_python/pybind11/tests/extra_python_package/test_files.py
ADDED
@@ -0,0 +1,279 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# -*- coding: utf-8 -*-
|
2 |
+
import contextlib
|
3 |
+
import os
|
4 |
+
import string
|
5 |
+
import subprocess
|
6 |
+
import sys
|
7 |
+
import tarfile
|
8 |
+
import zipfile
|
9 |
+
|
10 |
+
# These tests must be run explicitly
|
11 |
+
# They require CMake 3.15+ (--install)
|
12 |
+
|
13 |
+
DIR = os.path.abspath(os.path.dirname(__file__))
|
14 |
+
MAIN_DIR = os.path.dirname(os.path.dirname(DIR))
|
15 |
+
|
16 |
+
|
17 |
+
main_headers = {
|
18 |
+
"include/pybind11/attr.h",
|
19 |
+
"include/pybind11/buffer_info.h",
|
20 |
+
"include/pybind11/cast.h",
|
21 |
+
"include/pybind11/chrono.h",
|
22 |
+
"include/pybind11/common.h",
|
23 |
+
"include/pybind11/complex.h",
|
24 |
+
"include/pybind11/eigen.h",
|
25 |
+
"include/pybind11/embed.h",
|
26 |
+
"include/pybind11/eval.h",
|
27 |
+
"include/pybind11/functional.h",
|
28 |
+
"include/pybind11/gil.h",
|
29 |
+
"include/pybind11/iostream.h",
|
30 |
+
"include/pybind11/numpy.h",
|
31 |
+
"include/pybind11/operators.h",
|
32 |
+
"include/pybind11/options.h",
|
33 |
+
"include/pybind11/pybind11.h",
|
34 |
+
"include/pybind11/pytypes.h",
|
35 |
+
"include/pybind11/stl.h",
|
36 |
+
"include/pybind11/stl_bind.h",
|
37 |
+
}
|
38 |
+
|
39 |
+
detail_headers = {
|
40 |
+
"include/pybind11/detail/class.h",
|
41 |
+
"include/pybind11/detail/common.h",
|
42 |
+
"include/pybind11/detail/descr.h",
|
43 |
+
"include/pybind11/detail/init.h",
|
44 |
+
"include/pybind11/detail/internals.h",
|
45 |
+
"include/pybind11/detail/type_caster_base.h",
|
46 |
+
"include/pybind11/detail/typeid.h",
|
47 |
+
}
|
48 |
+
|
49 |
+
stl_headers = {
|
50 |
+
"include/pybind11/stl/filesystem.h",
|
51 |
+
}
|
52 |
+
|
53 |
+
cmake_files = {
|
54 |
+
"share/cmake/pybind11/FindPythonLibsNew.cmake",
|
55 |
+
"share/cmake/pybind11/pybind11Common.cmake",
|
56 |
+
"share/cmake/pybind11/pybind11Config.cmake",
|
57 |
+
"share/cmake/pybind11/pybind11ConfigVersion.cmake",
|
58 |
+
"share/cmake/pybind11/pybind11NewTools.cmake",
|
59 |
+
"share/cmake/pybind11/pybind11Targets.cmake",
|
60 |
+
"share/cmake/pybind11/pybind11Tools.cmake",
|
61 |
+
}
|
62 |
+
|
63 |
+
py_files = {
|
64 |
+
"__init__.py",
|
65 |
+
"__main__.py",
|
66 |
+
"_version.py",
|
67 |
+
"_version.pyi",
|
68 |
+
"commands.py",
|
69 |
+
"py.typed",
|
70 |
+
"setup_helpers.py",
|
71 |
+
"setup_helpers.pyi",
|
72 |
+
}
|
73 |
+
|
74 |
+
headers = main_headers | detail_headers | stl_headers
|
75 |
+
src_files = headers | cmake_files
|
76 |
+
all_files = src_files | py_files
|
77 |
+
|
78 |
+
|
79 |
+
sdist_files = {
|
80 |
+
"pybind11",
|
81 |
+
"pybind11/include",
|
82 |
+
"pybind11/include/pybind11",
|
83 |
+
"pybind11/include/pybind11/detail",
|
84 |
+
"pybind11/include/pybind11/stl",
|
85 |
+
"pybind11/share",
|
86 |
+
"pybind11/share/cmake",
|
87 |
+
"pybind11/share/cmake/pybind11",
|
88 |
+
"pyproject.toml",
|
89 |
+
"setup.cfg",
|
90 |
+
"setup.py",
|
91 |
+
"LICENSE",
|
92 |
+
"MANIFEST.in",
|
93 |
+
"README.rst",
|
94 |
+
"PKG-INFO",
|
95 |
+
}
|
96 |
+
|
97 |
+
local_sdist_files = {
|
98 |
+
".egg-info",
|
99 |
+
".egg-info/PKG-INFO",
|
100 |
+
".egg-info/SOURCES.txt",
|
101 |
+
".egg-info/dependency_links.txt",
|
102 |
+
".egg-info/not-zip-safe",
|
103 |
+
".egg-info/top_level.txt",
|
104 |
+
}
|
105 |
+
|
106 |
+
|
107 |
+
def test_build_sdist(monkeypatch, tmpdir):
|
108 |
+
|
109 |
+
monkeypatch.chdir(MAIN_DIR)
|
110 |
+
|
111 |
+
out = subprocess.check_output(
|
112 |
+
[
|
113 |
+
sys.executable,
|
114 |
+
"setup.py",
|
115 |
+
"sdist",
|
116 |
+
"--formats=tar",
|
117 |
+
"--dist-dir",
|
118 |
+
str(tmpdir),
|
119 |
+
]
|
120 |
+
)
|
121 |
+
if hasattr(out, "decode"):
|
122 |
+
out = out.decode()
|
123 |
+
|
124 |
+
(sdist,) = tmpdir.visit("*.tar")
|
125 |
+
|
126 |
+
with tarfile.open(str(sdist)) as tar:
|
127 |
+
start = tar.getnames()[0] + "/"
|
128 |
+
version = start[9:-1]
|
129 |
+
simpler = {n.split("/", 1)[-1] for n in tar.getnames()[1:]}
|
130 |
+
|
131 |
+
with contextlib.closing(
|
132 |
+
tar.extractfile(tar.getmember(start + "setup.py"))
|
133 |
+
) as f:
|
134 |
+
setup_py = f.read()
|
135 |
+
|
136 |
+
with contextlib.closing(
|
137 |
+
tar.extractfile(tar.getmember(start + "pyproject.toml"))
|
138 |
+
) as f:
|
139 |
+
pyproject_toml = f.read()
|
140 |
+
|
141 |
+
with contextlib.closing(
|
142 |
+
tar.extractfile(
|
143 |
+
tar.getmember(
|
144 |
+
start + "pybind11/share/cmake/pybind11/pybind11Config.cmake"
|
145 |
+
)
|
146 |
+
)
|
147 |
+
) as f:
|
148 |
+
contents = f.read().decode("utf8")
|
149 |
+
assert 'set(pybind11_INCLUDE_DIR "${PACKAGE_PREFIX_DIR}/include")' in contents
|
150 |
+
|
151 |
+
files = {"pybind11/{}".format(n) for n in all_files}
|
152 |
+
files |= sdist_files
|
153 |
+
files |= {"pybind11{}".format(n) for n in local_sdist_files}
|
154 |
+
files.add("pybind11.egg-info/entry_points.txt")
|
155 |
+
files.add("pybind11.egg-info/requires.txt")
|
156 |
+
assert simpler == files
|
157 |
+
|
158 |
+
with open(os.path.join(MAIN_DIR, "tools", "setup_main.py.in"), "rb") as f:
|
159 |
+
contents = (
|
160 |
+
string.Template(f.read().decode())
|
161 |
+
.substitute(version=version, extra_cmd="")
|
162 |
+
.encode()
|
163 |
+
)
|
164 |
+
assert setup_py == contents
|
165 |
+
|
166 |
+
with open(os.path.join(MAIN_DIR, "tools", "pyproject.toml"), "rb") as f:
|
167 |
+
contents = f.read()
|
168 |
+
assert pyproject_toml == contents
|
169 |
+
|
170 |
+
|
171 |
+
def test_build_global_dist(monkeypatch, tmpdir):
|
172 |
+
|
173 |
+
monkeypatch.chdir(MAIN_DIR)
|
174 |
+
monkeypatch.setenv("PYBIND11_GLOBAL_SDIST", "1")
|
175 |
+
|
176 |
+
out = subprocess.check_output(
|
177 |
+
[
|
178 |
+
sys.executable,
|
179 |
+
"setup.py",
|
180 |
+
"sdist",
|
181 |
+
"--formats=tar",
|
182 |
+
"--dist-dir",
|
183 |
+
str(tmpdir),
|
184 |
+
]
|
185 |
+
)
|
186 |
+
if hasattr(out, "decode"):
|
187 |
+
out = out.decode()
|
188 |
+
|
189 |
+
(sdist,) = tmpdir.visit("*.tar")
|
190 |
+
|
191 |
+
with tarfile.open(str(sdist)) as tar:
|
192 |
+
start = tar.getnames()[0] + "/"
|
193 |
+
version = start[16:-1]
|
194 |
+
simpler = {n.split("/", 1)[-1] for n in tar.getnames()[1:]}
|
195 |
+
|
196 |
+
with contextlib.closing(
|
197 |
+
tar.extractfile(tar.getmember(start + "setup.py"))
|
198 |
+
) as f:
|
199 |
+
setup_py = f.read()
|
200 |
+
|
201 |
+
with contextlib.closing(
|
202 |
+
tar.extractfile(tar.getmember(start + "pyproject.toml"))
|
203 |
+
) as f:
|
204 |
+
pyproject_toml = f.read()
|
205 |
+
|
206 |
+
files = {"pybind11/{}".format(n) for n in all_files}
|
207 |
+
files |= sdist_files
|
208 |
+
files |= {"pybind11_global{}".format(n) for n in local_sdist_files}
|
209 |
+
assert simpler == files
|
210 |
+
|
211 |
+
with open(os.path.join(MAIN_DIR, "tools", "setup_global.py.in"), "rb") as f:
|
212 |
+
contents = (
|
213 |
+
string.Template(f.read().decode())
|
214 |
+
.substitute(version=version, extra_cmd="")
|
215 |
+
.encode()
|
216 |
+
)
|
217 |
+
assert setup_py == contents
|
218 |
+
|
219 |
+
with open(os.path.join(MAIN_DIR, "tools", "pyproject.toml"), "rb") as f:
|
220 |
+
contents = f.read()
|
221 |
+
assert pyproject_toml == contents
|
222 |
+
|
223 |
+
|
224 |
+
def tests_build_wheel(monkeypatch, tmpdir):
|
225 |
+
monkeypatch.chdir(MAIN_DIR)
|
226 |
+
|
227 |
+
subprocess.check_output(
|
228 |
+
[sys.executable, "-m", "pip", "wheel", ".", "-w", str(tmpdir)]
|
229 |
+
)
|
230 |
+
|
231 |
+
(wheel,) = tmpdir.visit("*.whl")
|
232 |
+
|
233 |
+
files = {"pybind11/{}".format(n) for n in all_files}
|
234 |
+
files |= {
|
235 |
+
"dist-info/LICENSE",
|
236 |
+
"dist-info/METADATA",
|
237 |
+
"dist-info/RECORD",
|
238 |
+
"dist-info/WHEEL",
|
239 |
+
"dist-info/entry_points.txt",
|
240 |
+
"dist-info/top_level.txt",
|
241 |
+
}
|
242 |
+
|
243 |
+
with zipfile.ZipFile(str(wheel)) as z:
|
244 |
+
names = z.namelist()
|
245 |
+
|
246 |
+
trimmed = {n for n in names if "dist-info" not in n}
|
247 |
+
trimmed |= {
|
248 |
+
"dist-info/{}".format(n.split("/", 1)[-1]) for n in names if "dist-info" in n
|
249 |
+
}
|
250 |
+
assert files == trimmed
|
251 |
+
|
252 |
+
|
253 |
+
def tests_build_global_wheel(monkeypatch, tmpdir):
|
254 |
+
monkeypatch.chdir(MAIN_DIR)
|
255 |
+
monkeypatch.setenv("PYBIND11_GLOBAL_SDIST", "1")
|
256 |
+
|
257 |
+
subprocess.check_output(
|
258 |
+
[sys.executable, "-m", "pip", "wheel", ".", "-w", str(tmpdir)]
|
259 |
+
)
|
260 |
+
|
261 |
+
(wheel,) = tmpdir.visit("*.whl")
|
262 |
+
|
263 |
+
files = {"data/data/{}".format(n) for n in src_files}
|
264 |
+
files |= {"data/headers/{}".format(n[8:]) for n in headers}
|
265 |
+
files |= {
|
266 |
+
"dist-info/LICENSE",
|
267 |
+
"dist-info/METADATA",
|
268 |
+
"dist-info/WHEEL",
|
269 |
+
"dist-info/top_level.txt",
|
270 |
+
"dist-info/RECORD",
|
271 |
+
}
|
272 |
+
|
273 |
+
with zipfile.ZipFile(str(wheel)) as z:
|
274 |
+
names = z.namelist()
|
275 |
+
|
276 |
+
beginning = names[0].split("/", 1)[0].rsplit(".", 1)[0]
|
277 |
+
trimmed = {n[len(beginning) + 1 :] for n in names}
|
278 |
+
|
279 |
+
assert files == trimmed
|
third-party/DPVO/Pangolin/components/pango_python/pybind11/tests/extra_setuptools/pytest.ini
ADDED
File without changes
|
third-party/DPVO/Pangolin/components/pango_python/pybind11/tests/extra_setuptools/test_setuphelper.py
ADDED
@@ -0,0 +1,143 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# -*- coding: utf-8 -*-
|
2 |
+
import os
|
3 |
+
import sys
|
4 |
+
import subprocess
|
5 |
+
from textwrap import dedent
|
6 |
+
|
7 |
+
import pytest
|
8 |
+
|
9 |
+
DIR = os.path.abspath(os.path.dirname(__file__))
|
10 |
+
MAIN_DIR = os.path.dirname(os.path.dirname(DIR))
|
11 |
+
|
12 |
+
|
13 |
+
@pytest.mark.parametrize("parallel", [False, True])
|
14 |
+
@pytest.mark.parametrize("std", [11, 0])
|
15 |
+
def test_simple_setup_py(monkeypatch, tmpdir, parallel, std):
|
16 |
+
monkeypatch.chdir(tmpdir)
|
17 |
+
monkeypatch.syspath_prepend(MAIN_DIR)
|
18 |
+
|
19 |
+
(tmpdir / "setup.py").write_text(
|
20 |
+
dedent(
|
21 |
+
u"""\
|
22 |
+
import sys
|
23 |
+
sys.path.append({MAIN_DIR!r})
|
24 |
+
|
25 |
+
from setuptools import setup, Extension
|
26 |
+
from pybind11.setup_helpers import build_ext, Pybind11Extension
|
27 |
+
|
28 |
+
std = {std}
|
29 |
+
|
30 |
+
ext_modules = [
|
31 |
+
Pybind11Extension(
|
32 |
+
"simple_setup",
|
33 |
+
sorted(["main.cpp"]),
|
34 |
+
cxx_std=std,
|
35 |
+
),
|
36 |
+
]
|
37 |
+
|
38 |
+
cmdclass = dict()
|
39 |
+
if std == 0:
|
40 |
+
cmdclass["build_ext"] = build_ext
|
41 |
+
|
42 |
+
|
43 |
+
parallel = {parallel}
|
44 |
+
if parallel:
|
45 |
+
from pybind11.setup_helpers import ParallelCompile
|
46 |
+
ParallelCompile().install()
|
47 |
+
|
48 |
+
setup(
|
49 |
+
name="simple_setup_package",
|
50 |
+
cmdclass=cmdclass,
|
51 |
+
ext_modules=ext_modules,
|
52 |
+
)
|
53 |
+
"""
|
54 |
+
).format(MAIN_DIR=MAIN_DIR, std=std, parallel=parallel),
|
55 |
+
encoding="ascii",
|
56 |
+
)
|
57 |
+
|
58 |
+
(tmpdir / "main.cpp").write_text(
|
59 |
+
dedent(
|
60 |
+
u"""\
|
61 |
+
#include <pybind11/pybind11.h>
|
62 |
+
|
63 |
+
int f(int x) {
|
64 |
+
return x * 3;
|
65 |
+
}
|
66 |
+
PYBIND11_MODULE(simple_setup, m) {
|
67 |
+
m.def("f", &f);
|
68 |
+
}
|
69 |
+
"""
|
70 |
+
),
|
71 |
+
encoding="ascii",
|
72 |
+
)
|
73 |
+
|
74 |
+
subprocess.check_call(
|
75 |
+
[sys.executable, "setup.py", "build_ext", "--inplace"],
|
76 |
+
stdout=sys.stdout,
|
77 |
+
stderr=sys.stderr,
|
78 |
+
)
|
79 |
+
|
80 |
+
# Debug helper printout, normally hidden
|
81 |
+
for item in tmpdir.listdir():
|
82 |
+
print(item.basename)
|
83 |
+
|
84 |
+
assert (
|
85 |
+
len([f for f in tmpdir.listdir() if f.basename.startswith("simple_setup")]) == 1
|
86 |
+
)
|
87 |
+
assert len(list(tmpdir.listdir())) == 4 # two files + output + build_dir
|
88 |
+
|
89 |
+
(tmpdir / "test.py").write_text(
|
90 |
+
dedent(
|
91 |
+
u"""\
|
92 |
+
import simple_setup
|
93 |
+
assert simple_setup.f(3) == 9
|
94 |
+
"""
|
95 |
+
),
|
96 |
+
encoding="ascii",
|
97 |
+
)
|
98 |
+
|
99 |
+
subprocess.check_call(
|
100 |
+
[sys.executable, "test.py"], stdout=sys.stdout, stderr=sys.stderr
|
101 |
+
)
|
102 |
+
|
103 |
+
|
104 |
+
def test_intree_extensions(monkeypatch, tmpdir):
|
105 |
+
monkeypatch.syspath_prepend(MAIN_DIR)
|
106 |
+
|
107 |
+
from pybind11.setup_helpers import intree_extensions
|
108 |
+
|
109 |
+
monkeypatch.chdir(tmpdir)
|
110 |
+
root = tmpdir
|
111 |
+
root.ensure_dir()
|
112 |
+
subdir = root / "dir"
|
113 |
+
subdir.ensure_dir()
|
114 |
+
src = subdir / "ext.cpp"
|
115 |
+
src.ensure()
|
116 |
+
(ext,) = intree_extensions([src.relto(tmpdir)])
|
117 |
+
assert ext.name == "ext"
|
118 |
+
subdir.ensure("__init__.py")
|
119 |
+
(ext,) = intree_extensions([src.relto(tmpdir)])
|
120 |
+
assert ext.name == "dir.ext"
|
121 |
+
|
122 |
+
|
123 |
+
def test_intree_extensions_package_dir(monkeypatch, tmpdir):
|
124 |
+
monkeypatch.syspath_prepend(MAIN_DIR)
|
125 |
+
|
126 |
+
from pybind11.setup_helpers import intree_extensions
|
127 |
+
|
128 |
+
monkeypatch.chdir(tmpdir)
|
129 |
+
root = tmpdir / "src"
|
130 |
+
root.ensure_dir()
|
131 |
+
subdir = root / "dir"
|
132 |
+
subdir.ensure_dir()
|
133 |
+
src = subdir / "ext.cpp"
|
134 |
+
src.ensure()
|
135 |
+
(ext,) = intree_extensions([src.relto(tmpdir)], package_dir={"": "src"})
|
136 |
+
assert ext.name == "dir.ext"
|
137 |
+
(ext,) = intree_extensions([src.relto(tmpdir)], package_dir={"foo": "src"})
|
138 |
+
assert ext.name == "foo.dir.ext"
|
139 |
+
subdir.ensure("__init__.py")
|
140 |
+
(ext,) = intree_extensions([src.relto(tmpdir)], package_dir={"": "src"})
|
141 |
+
assert ext.name == "dir.ext"
|
142 |
+
(ext,) = intree_extensions([src.relto(tmpdir)], package_dir={"foo": "src"})
|
143 |
+
assert ext.name == "foo.dir.ext"
|
third-party/DPVO/Pangolin/components/pango_python/pybind11/tests/local_bindings.h
ADDED
@@ -0,0 +1,66 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
#pragma once
|
2 |
+
#include <utility>
|
3 |
+
|
4 |
+
#include "pybind11_tests.h"
|
5 |
+
|
6 |
+
/// Simple class used to test py::local:
|
7 |
+
template <int> class LocalBase {
|
8 |
+
public:
|
9 |
+
LocalBase(int i) : i(i) { }
|
10 |
+
int i = -1;
|
11 |
+
};
|
12 |
+
|
13 |
+
/// Registered with py::module_local in both main and secondary modules:
|
14 |
+
using LocalType = LocalBase<0>;
|
15 |
+
/// Registered without py::module_local in both modules:
|
16 |
+
using NonLocalType = LocalBase<1>;
|
17 |
+
/// A second non-local type (for stl_bind tests):
|
18 |
+
using NonLocal2 = LocalBase<2>;
|
19 |
+
/// Tests within-module, different-compilation-unit local definition conflict:
|
20 |
+
using LocalExternal = LocalBase<3>;
|
21 |
+
/// Mixed: registered local first, then global
|
22 |
+
using MixedLocalGlobal = LocalBase<4>;
|
23 |
+
/// Mixed: global first, then local
|
24 |
+
using MixedGlobalLocal = LocalBase<5>;
|
25 |
+
|
26 |
+
/// Registered with py::module_local only in the secondary module:
|
27 |
+
using ExternalType1 = LocalBase<6>;
|
28 |
+
using ExternalType2 = LocalBase<7>;
|
29 |
+
|
30 |
+
using LocalVec = std::vector<LocalType>;
|
31 |
+
using LocalVec2 = std::vector<NonLocal2>;
|
32 |
+
using LocalMap = std::unordered_map<std::string, LocalType>;
|
33 |
+
using NonLocalVec = std::vector<NonLocalType>;
|
34 |
+
using NonLocalVec2 = std::vector<NonLocal2>;
|
35 |
+
using NonLocalMap = std::unordered_map<std::string, NonLocalType>;
|
36 |
+
using NonLocalMap2 = std::unordered_map<std::string, uint8_t>;
|
37 |
+
|
38 |
+
PYBIND11_MAKE_OPAQUE(LocalVec);
|
39 |
+
PYBIND11_MAKE_OPAQUE(LocalVec2);
|
40 |
+
PYBIND11_MAKE_OPAQUE(LocalMap);
|
41 |
+
PYBIND11_MAKE_OPAQUE(NonLocalVec);
|
42 |
+
//PYBIND11_MAKE_OPAQUE(NonLocalVec2); // same type as LocalVec2
|
43 |
+
PYBIND11_MAKE_OPAQUE(NonLocalMap);
|
44 |
+
PYBIND11_MAKE_OPAQUE(NonLocalMap2);
|
45 |
+
|
46 |
+
|
47 |
+
// Simple bindings (used with the above):
|
48 |
+
template <typename T, int Adjust = 0, typename... Args>
|
49 |
+
py::class_<T> bind_local(Args && ...args) {
|
50 |
+
return py::class_<T>(std::forward<Args>(args)...)
|
51 |
+
.def(py::init<int>())
|
52 |
+
.def("get", [](T &i) { return i.i + Adjust; });
|
53 |
+
};
|
54 |
+
|
55 |
+
// Simulate a foreign library base class (to match the example in the docs):
|
56 |
+
namespace pets {
|
57 |
+
class Pet {
|
58 |
+
public:
|
59 |
+
Pet(std::string name) : name_(std::move(name)) {}
|
60 |
+
std::string name_;
|
61 |
+
const std::string &name() const { return name_; }
|
62 |
+
};
|
63 |
+
} // namespace pets
|
64 |
+
|
65 |
+
struct MixGL { int i; MixGL(int i) : i{i} {} };
|
66 |
+
struct MixGL2 { int i; MixGL2(int i) : i{i} {} };
|
third-party/DPVO/Pangolin/components/pango_python/pybind11/tests/object.h
ADDED
@@ -0,0 +1,175 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
#if !defined(__OBJECT_H)
|
2 |
+
#define __OBJECT_H
|
3 |
+
|
4 |
+
#include <atomic>
|
5 |
+
#include "constructor_stats.h"
|
6 |
+
|
7 |
+
/// Reference counted object base class
|
8 |
+
class Object {
|
9 |
+
public:
|
10 |
+
/// Default constructor
|
11 |
+
Object() { print_default_created(this); }
|
12 |
+
|
13 |
+
/// Copy constructor
|
14 |
+
Object(const Object &) : m_refCount(0) { print_copy_created(this); }
|
15 |
+
|
16 |
+
/// Return the current reference count
|
17 |
+
int getRefCount() const { return m_refCount; };
|
18 |
+
|
19 |
+
/// Increase the object's reference count by one
|
20 |
+
void incRef() const { ++m_refCount; }
|
21 |
+
|
22 |
+
/** \brief Decrease the reference count of
|
23 |
+
* the object and possibly deallocate it.
|
24 |
+
*
|
25 |
+
* The object will automatically be deallocated once
|
26 |
+
* the reference count reaches zero.
|
27 |
+
*/
|
28 |
+
void decRef(bool dealloc = true) const {
|
29 |
+
--m_refCount;
|
30 |
+
if (m_refCount == 0 && dealloc)
|
31 |
+
delete this;
|
32 |
+
else if (m_refCount < 0)
|
33 |
+
throw std::runtime_error("Internal error: reference count < 0!");
|
34 |
+
}
|
35 |
+
|
36 |
+
virtual std::string toString() const = 0;
|
37 |
+
protected:
|
38 |
+
/** \brief Virtual protected deconstructor.
|
39 |
+
* (Will only be called by \ref ref)
|
40 |
+
*/
|
41 |
+
virtual ~Object() { print_destroyed(this); }
|
42 |
+
private:
|
43 |
+
mutable std::atomic<int> m_refCount { 0 };
|
44 |
+
};
|
45 |
+
|
46 |
+
// Tag class used to track constructions of ref objects. When we track constructors, below, we
|
47 |
+
// track and print out the actual class (e.g. ref<MyObject>), and *also* add a fake tracker for
|
48 |
+
// ref_tag. This lets us check that the total number of ref<Anything> constructors/destructors is
|
49 |
+
// correct without having to check each individual ref<Whatever> type individually.
|
50 |
+
class ref_tag {};
|
51 |
+
|
52 |
+
/**
|
53 |
+
* \brief Reference counting helper
|
54 |
+
*
|
55 |
+
* The \a ref refeference template is a simple wrapper to store a
|
56 |
+
* pointer to an object. It takes care of increasing and decreasing
|
57 |
+
* the reference count of the object. When the last reference goes
|
58 |
+
* out of scope, the associated object will be deallocated.
|
59 |
+
*
|
60 |
+
* \ingroup libcore
|
61 |
+
*/
|
62 |
+
template <typename T> class ref {
|
63 |
+
public:
|
64 |
+
/// Create a nullptr reference
|
65 |
+
ref() : m_ptr(nullptr) { print_default_created(this); track_default_created((ref_tag*) this); }
|
66 |
+
|
67 |
+
/// Construct a reference from a pointer
|
68 |
+
ref(T *ptr) : m_ptr(ptr) {
|
69 |
+
if (m_ptr) ((Object *) m_ptr)->incRef();
|
70 |
+
|
71 |
+
print_created(this, "from pointer", m_ptr); track_created((ref_tag*) this, "from pointer");
|
72 |
+
|
73 |
+
}
|
74 |
+
|
75 |
+
/// Copy constructor
|
76 |
+
ref(const ref &r) : m_ptr(r.m_ptr) {
|
77 |
+
if (m_ptr)
|
78 |
+
((Object *) m_ptr)->incRef();
|
79 |
+
|
80 |
+
print_copy_created(this, "with pointer", m_ptr); track_copy_created((ref_tag*) this);
|
81 |
+
}
|
82 |
+
|
83 |
+
/// Move constructor
|
84 |
+
ref(ref &&r) noexcept : m_ptr(r.m_ptr) {
|
85 |
+
r.m_ptr = nullptr;
|
86 |
+
|
87 |
+
print_move_created(this, "with pointer", m_ptr); track_move_created((ref_tag*) this);
|
88 |
+
}
|
89 |
+
|
90 |
+
/// Destroy this reference
|
91 |
+
~ref() {
|
92 |
+
if (m_ptr)
|
93 |
+
((Object *) m_ptr)->decRef();
|
94 |
+
|
95 |
+
print_destroyed(this); track_destroyed((ref_tag*) this);
|
96 |
+
}
|
97 |
+
|
98 |
+
/// Move another reference into the current one
|
99 |
+
ref &operator=(ref &&r) noexcept {
|
100 |
+
print_move_assigned(this, "pointer", r.m_ptr); track_move_assigned((ref_tag*) this);
|
101 |
+
|
102 |
+
if (*this == r)
|
103 |
+
return *this;
|
104 |
+
if (m_ptr)
|
105 |
+
((Object *) m_ptr)->decRef();
|
106 |
+
m_ptr = r.m_ptr;
|
107 |
+
r.m_ptr = nullptr;
|
108 |
+
return *this;
|
109 |
+
}
|
110 |
+
|
111 |
+
/// Overwrite this reference with another reference
|
112 |
+
ref& operator=(const ref& r) {
|
113 |
+
print_copy_assigned(this, "pointer", r.m_ptr); track_copy_assigned((ref_tag*) this);
|
114 |
+
|
115 |
+
if (m_ptr == r.m_ptr)
|
116 |
+
return *this;
|
117 |
+
if (m_ptr)
|
118 |
+
((Object *) m_ptr)->decRef();
|
119 |
+
m_ptr = r.m_ptr;
|
120 |
+
if (m_ptr)
|
121 |
+
((Object *) m_ptr)->incRef();
|
122 |
+
return *this;
|
123 |
+
}
|
124 |
+
|
125 |
+
/// Overwrite this reference with a pointer to another object
|
126 |
+
ref& operator=(T *ptr) {
|
127 |
+
print_values(this, "assigned pointer"); track_values((ref_tag*) this, "assigned pointer");
|
128 |
+
|
129 |
+
if (m_ptr == ptr)
|
130 |
+
return *this;
|
131 |
+
if (m_ptr)
|
132 |
+
((Object *) m_ptr)->decRef();
|
133 |
+
m_ptr = ptr;
|
134 |
+
if (m_ptr)
|
135 |
+
((Object *) m_ptr)->incRef();
|
136 |
+
return *this;
|
137 |
+
}
|
138 |
+
|
139 |
+
/// Compare this reference with another reference
|
140 |
+
bool operator==(const ref &r) const { return m_ptr == r.m_ptr; }
|
141 |
+
|
142 |
+
/// Compare this reference with another reference
|
143 |
+
bool operator!=(const ref &r) const { return m_ptr != r.m_ptr; }
|
144 |
+
|
145 |
+
/// Compare this reference with a pointer
|
146 |
+
bool operator==(const T* ptr) const { return m_ptr == ptr; }
|
147 |
+
|
148 |
+
/// Compare this reference with a pointer
|
149 |
+
bool operator!=(const T* ptr) const { return m_ptr != ptr; }
|
150 |
+
|
151 |
+
/// Access the object referenced by this reference
|
152 |
+
T* operator->() { return m_ptr; }
|
153 |
+
|
154 |
+
/// Access the object referenced by this reference
|
155 |
+
const T* operator->() const { return m_ptr; }
|
156 |
+
|
157 |
+
/// Return a C++ reference to the referenced object
|
158 |
+
T& operator*() { return *m_ptr; }
|
159 |
+
|
160 |
+
/// Return a const C++ reference to the referenced object
|
161 |
+
const T& operator*() const { return *m_ptr; }
|
162 |
+
|
163 |
+
/// Return a pointer to the referenced object
|
164 |
+
operator T* () { return m_ptr; }
|
165 |
+
|
166 |
+
/// Return a const pointer to the referenced object
|
167 |
+
T* get_ptr() { return m_ptr; }
|
168 |
+
|
169 |
+
/// Return a pointer to the referenced object
|
170 |
+
const T* get_ptr() const { return m_ptr; }
|
171 |
+
private:
|
172 |
+
T *m_ptr;
|
173 |
+
};
|
174 |
+
|
175 |
+
#endif /* __OBJECT_H */
|
third-party/DPVO/Pangolin/components/pango_python/pybind11/tests/pybind11_cross_module_tests.cpp
ADDED
@@ -0,0 +1,137 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/*
|
2 |
+
tests/pybind11_cross_module_tests.cpp -- contains tests that require multiple modules
|
3 |
+
|
4 |
+
Copyright (c) 2017 Jason Rhinelander <[email protected]>
|
5 |
+
|
6 |
+
All rights reserved. Use of this source code is governed by a
|
7 |
+
BSD-style license that can be found in the LICENSE file.
|
8 |
+
*/
|
9 |
+
|
10 |
+
#include "pybind11_tests.h"
|
11 |
+
#include "local_bindings.h"
|
12 |
+
#include "test_exceptions.h"
|
13 |
+
|
14 |
+
#include <pybind11/stl_bind.h>
|
15 |
+
|
16 |
+
#include <numeric>
|
17 |
+
#include <utility>
|
18 |
+
|
19 |
+
PYBIND11_MODULE(pybind11_cross_module_tests, m) {
|
20 |
+
m.doc() = "pybind11 cross-module test module";
|
21 |
+
|
22 |
+
// test_local_bindings.py tests:
|
23 |
+
//
|
24 |
+
// Definitions here are tested by importing both this module and the
|
25 |
+
// relevant pybind11_tests submodule from a test_whatever.py
|
26 |
+
|
27 |
+
// test_load_external
|
28 |
+
bind_local<ExternalType1>(m, "ExternalType1", py::module_local());
|
29 |
+
bind_local<ExternalType2>(m, "ExternalType2", py::module_local());
|
30 |
+
|
31 |
+
// test_exceptions.py
|
32 |
+
m.def("raise_runtime_error", []() { PyErr_SetString(PyExc_RuntimeError, "My runtime error"); throw py::error_already_set(); });
|
33 |
+
m.def("raise_value_error", []() { PyErr_SetString(PyExc_ValueError, "My value error"); throw py::error_already_set(); });
|
34 |
+
m.def("throw_pybind_value_error", []() { throw py::value_error("pybind11 value error"); });
|
35 |
+
m.def("throw_pybind_type_error", []() { throw py::type_error("pybind11 type error"); });
|
36 |
+
m.def("throw_stop_iteration", []() { throw py::stop_iteration(); });
|
37 |
+
py::register_exception_translator([](std::exception_ptr p) {
|
38 |
+
try {
|
39 |
+
if (p) std::rethrow_exception(p);
|
40 |
+
} catch (const shared_exception &e) {
|
41 |
+
PyErr_SetString(PyExc_KeyError, e.what());
|
42 |
+
}
|
43 |
+
});
|
44 |
+
|
45 |
+
// test_local_bindings.py
|
46 |
+
// Local to both:
|
47 |
+
bind_local<LocalType, 1>(m, "LocalType", py::module_local())
|
48 |
+
.def("get2", [](LocalType &t) { return t.i + 2; })
|
49 |
+
;
|
50 |
+
|
51 |
+
// Can only be called with our python type:
|
52 |
+
m.def("local_value", [](LocalType &l) { return l.i; });
|
53 |
+
|
54 |
+
// test_nonlocal_failure
|
55 |
+
// This registration will fail (global registration when LocalFail is already registered
|
56 |
+
// globally in the main test module):
|
57 |
+
m.def("register_nonlocal", [m]() {
|
58 |
+
bind_local<NonLocalType, 0>(m, "NonLocalType");
|
59 |
+
});
|
60 |
+
|
61 |
+
// test_stl_bind_local
|
62 |
+
// stl_bind.h binders defaults to py::module_local if the types are local or converting:
|
63 |
+
py::bind_vector<LocalVec>(m, "LocalVec");
|
64 |
+
py::bind_map<LocalMap>(m, "LocalMap");
|
65 |
+
|
66 |
+
// test_stl_bind_global
|
67 |
+
// and global if the type (or one of the types, for the map) is global (so these will fail,
|
68 |
+
// assuming pybind11_tests is already loaded):
|
69 |
+
m.def("register_nonlocal_vec", [m]() {
|
70 |
+
py::bind_vector<NonLocalVec>(m, "NonLocalVec");
|
71 |
+
});
|
72 |
+
m.def("register_nonlocal_map", [m]() {
|
73 |
+
py::bind_map<NonLocalMap>(m, "NonLocalMap");
|
74 |
+
});
|
75 |
+
// The default can, however, be overridden to global using `py::module_local()` or
|
76 |
+
// `py::module_local(false)`.
|
77 |
+
// Explicitly made local:
|
78 |
+
py::bind_vector<NonLocalVec2>(m, "NonLocalVec2", py::module_local());
|
79 |
+
// Explicitly made global (and so will fail to bind):
|
80 |
+
m.def("register_nonlocal_map2", [m]() {
|
81 |
+
py::bind_map<NonLocalMap2>(m, "NonLocalMap2", py::module_local(false));
|
82 |
+
});
|
83 |
+
|
84 |
+
// test_mixed_local_global
|
85 |
+
// We try this both with the global type registered first and vice versa (the order shouldn't
|
86 |
+
// matter).
|
87 |
+
m.def("register_mixed_global_local", [m]() {
|
88 |
+
bind_local<MixedGlobalLocal, 200>(m, "MixedGlobalLocal", py::module_local());
|
89 |
+
});
|
90 |
+
m.def("register_mixed_local_global", [m]() {
|
91 |
+
bind_local<MixedLocalGlobal, 2000>(m, "MixedLocalGlobal", py::module_local(false));
|
92 |
+
});
|
93 |
+
m.def("get_mixed_gl", [](int i) { return MixedGlobalLocal(i); });
|
94 |
+
m.def("get_mixed_lg", [](int i) { return MixedLocalGlobal(i); });
|
95 |
+
|
96 |
+
// test_internal_locals_differ
|
97 |
+
m.def("local_cpp_types_addr", []() { return (uintptr_t) &py::detail::registered_local_types_cpp(); });
|
98 |
+
|
99 |
+
// test_stl_caster_vs_stl_bind
|
100 |
+
py::bind_vector<std::vector<int>>(m, "VectorInt");
|
101 |
+
|
102 |
+
m.def("load_vector_via_binding", [](std::vector<int> &v) {
|
103 |
+
return std::accumulate(v.begin(), v.end(), 0);
|
104 |
+
});
|
105 |
+
|
106 |
+
// test_cross_module_calls
|
107 |
+
m.def("return_self", [](LocalVec *v) { return v; });
|
108 |
+
m.def("return_copy", [](const LocalVec &v) { return LocalVec(v); });
|
109 |
+
|
110 |
+
class Dog : public pets::Pet {
|
111 |
+
public:
|
112 |
+
Dog(std::string name) : Pet(std::move(name)) {}
|
113 |
+
};
|
114 |
+
py::class_<pets::Pet>(m, "Pet", py::module_local())
|
115 |
+
.def("name", &pets::Pet::name);
|
116 |
+
// Binding for local extending class:
|
117 |
+
py::class_<Dog, pets::Pet>(m, "Dog")
|
118 |
+
.def(py::init<std::string>());
|
119 |
+
m.def("pet_name", [](pets::Pet &p) { return p.name(); });
|
120 |
+
|
121 |
+
py::class_<MixGL>(m, "MixGL", py::module_local()).def(py::init<int>());
|
122 |
+
m.def("get_gl_value", [](MixGL &o) { return o.i + 100; });
|
123 |
+
|
124 |
+
py::class_<MixGL2>(m, "MixGL2", py::module_local()).def(py::init<int>());
|
125 |
+
|
126 |
+
// test_vector_bool
|
127 |
+
// We can't test both stl.h and stl_bind.h conversions of `std::vector<bool>` within
|
128 |
+
// the same module (it would be an ODR violation). Therefore `bind_vector` of `bool`
|
129 |
+
// is defined here and tested in `test_stl_binders.py`.
|
130 |
+
py::bind_vector<std::vector<bool>>(m, "VectorBool");
|
131 |
+
|
132 |
+
// test_missing_header_message
|
133 |
+
// The main module already includes stl.h, but we need to test the error message
|
134 |
+
// which appears when this header is missing.
|
135 |
+
m.def("missing_header_arg", [](const std::vector<float> &) {});
|
136 |
+
m.def("missing_header_return", []() { return std::vector<float>(); });
|
137 |
+
}
|
third-party/DPVO/Pangolin/components/pango_python/pybind11/tests/pybind11_tests.cpp
ADDED
@@ -0,0 +1,91 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/*
|
2 |
+
tests/pybind11_tests.cpp -- pybind example plugin
|
3 |
+
|
4 |
+
Copyright (c) 2016 Wenzel Jakob <[email protected]>
|
5 |
+
|
6 |
+
All rights reserved. Use of this source code is governed by a
|
7 |
+
BSD-style license that can be found in the LICENSE file.
|
8 |
+
*/
|
9 |
+
|
10 |
+
#include "pybind11_tests.h"
|
11 |
+
#include "constructor_stats.h"
|
12 |
+
|
13 |
+
#include <functional>
|
14 |
+
#include <list>
|
15 |
+
|
16 |
+
/*
|
17 |
+
For testing purposes, we define a static global variable here in a function that each individual
|
18 |
+
test .cpp calls with its initialization lambda. It's convenient here because we can just not
|
19 |
+
compile some test files to disable/ignore some of the test code.
|
20 |
+
|
21 |
+
It is NOT recommended as a way to use pybind11 in practice, however: the initialization order will
|
22 |
+
be essentially random, which is okay for our test scripts (there are no dependencies between the
|
23 |
+
individual pybind11 test .cpp files), but most likely not what you want when using pybind11
|
24 |
+
productively.
|
25 |
+
|
26 |
+
Instead, see the "How can I reduce the build time?" question in the "Frequently asked questions"
|
27 |
+
section of the documentation for good practice on splitting binding code over multiple files.
|
28 |
+
*/
|
29 |
+
std::list<std::function<void(py::module_ &)>> &initializers() {
|
30 |
+
static std::list<std::function<void(py::module_ &)>> inits;
|
31 |
+
return inits;
|
32 |
+
}
|
33 |
+
|
34 |
+
test_initializer::test_initializer(Initializer init) {
|
35 |
+
initializers().emplace_back(init);
|
36 |
+
}
|
37 |
+
|
38 |
+
test_initializer::test_initializer(const char *submodule_name, Initializer init) {
|
39 |
+
initializers().emplace_back([=](py::module_ &parent) {
|
40 |
+
auto m = parent.def_submodule(submodule_name);
|
41 |
+
init(m);
|
42 |
+
});
|
43 |
+
}
|
44 |
+
|
45 |
+
void bind_ConstructorStats(py::module_ &m) {
|
46 |
+
py::class_<ConstructorStats>(m, "ConstructorStats")
|
47 |
+
.def("alive", &ConstructorStats::alive)
|
48 |
+
.def("values", &ConstructorStats::values)
|
49 |
+
.def_readwrite("default_constructions", &ConstructorStats::default_constructions)
|
50 |
+
.def_readwrite("copy_assignments", &ConstructorStats::copy_assignments)
|
51 |
+
.def_readwrite("move_assignments", &ConstructorStats::move_assignments)
|
52 |
+
.def_readwrite("copy_constructions", &ConstructorStats::copy_constructions)
|
53 |
+
.def_readwrite("move_constructions", &ConstructorStats::move_constructions)
|
54 |
+
.def_static("get", (ConstructorStats &(*)(py::object)) &ConstructorStats::get, py::return_value_policy::reference_internal)
|
55 |
+
|
56 |
+
// Not exactly ConstructorStats, but related: expose the internal pybind number of registered instances
|
57 |
+
// to allow instance cleanup checks (invokes a GC first)
|
58 |
+
.def_static("detail_reg_inst", []() {
|
59 |
+
ConstructorStats::gc();
|
60 |
+
return py::detail::get_internals().registered_instances.size();
|
61 |
+
})
|
62 |
+
;
|
63 |
+
}
|
64 |
+
|
65 |
+
PYBIND11_MODULE(pybind11_tests, m) {
|
66 |
+
m.doc() = "pybind11 test module";
|
67 |
+
|
68 |
+
bind_ConstructorStats(m);
|
69 |
+
|
70 |
+
#if !defined(NDEBUG)
|
71 |
+
m.attr("debug_enabled") = true;
|
72 |
+
#else
|
73 |
+
m.attr("debug_enabled") = false;
|
74 |
+
#endif
|
75 |
+
|
76 |
+
py::class_<UserType>(m, "UserType", "A `py::class_` type for testing")
|
77 |
+
.def(py::init<>())
|
78 |
+
.def(py::init<int>())
|
79 |
+
.def("get_value", &UserType::value, "Get value using a method")
|
80 |
+
.def("set_value", &UserType::set, "Set value using a method")
|
81 |
+
.def_property("value", &UserType::value, &UserType::set, "Get/set value using a property")
|
82 |
+
.def("__repr__", [](const UserType& u) { return "UserType({})"_s.format(u.value()); });
|
83 |
+
|
84 |
+
py::class_<IncType, UserType>(m, "IncType")
|
85 |
+
.def(py::init<>())
|
86 |
+
.def(py::init<int>())
|
87 |
+
.def("__repr__", [](const IncType& u) { return "IncType({})"_s.format(u.value()); });
|
88 |
+
|
89 |
+
for (const auto &initializer : initializers())
|
90 |
+
initializer(m);
|
91 |
+
}
|
third-party/DPVO/Pangolin/components/pango_python/pybind11/tests/pybind11_tests.h
ADDED
@@ -0,0 +1,89 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
#pragma once
|
2 |
+
|
3 |
+
// This must be kept first for MSVC 2015.
|
4 |
+
// Do not remove the empty line between the #includes.
|
5 |
+
#include <pybind11/pybind11.h>
|
6 |
+
|
7 |
+
#include <pybind11/eval.h>
|
8 |
+
|
9 |
+
#if defined(_MSC_VER) && _MSC_VER < 1910
|
10 |
+
// We get some really long type names here which causes MSVC 2015 to emit warnings
|
11 |
+
# pragma warning( \
|
12 |
+
disable : 4503) // warning C4503: decorated name length exceeded, name was truncated
|
13 |
+
#endif
|
14 |
+
|
15 |
+
namespace py = pybind11;
|
16 |
+
using namespace pybind11::literals;
|
17 |
+
|
18 |
+
class test_initializer {
|
19 |
+
using Initializer = void (*)(py::module_ &);
|
20 |
+
|
21 |
+
public:
|
22 |
+
test_initializer(Initializer init);
|
23 |
+
test_initializer(const char *submodule_name, Initializer init);
|
24 |
+
};
|
25 |
+
|
26 |
+
#define TEST_SUBMODULE(name, variable) \
|
27 |
+
void test_submodule_##name(py::module_ &); \
|
28 |
+
test_initializer name(#name, test_submodule_##name); \
|
29 |
+
void test_submodule_##name(py::module_ &variable)
|
30 |
+
|
31 |
+
|
32 |
+
/// Dummy type which is not exported anywhere -- something to trigger a conversion error
|
33 |
+
struct UnregisteredType { };
|
34 |
+
|
35 |
+
/// A user-defined type which is exported and can be used by any test
|
36 |
+
class UserType {
|
37 |
+
public:
|
38 |
+
UserType() = default;
|
39 |
+
UserType(int i) : i(i) { }
|
40 |
+
|
41 |
+
int value() const { return i; }
|
42 |
+
void set(int set) { i = set; }
|
43 |
+
|
44 |
+
private:
|
45 |
+
int i = -1;
|
46 |
+
};
|
47 |
+
|
48 |
+
/// Like UserType, but increments `value` on copy for quick reference vs. copy tests
|
49 |
+
class IncType : public UserType {
|
50 |
+
public:
|
51 |
+
using UserType::UserType;
|
52 |
+
IncType() = default;
|
53 |
+
IncType(const IncType &other) : IncType(other.value() + 1) { }
|
54 |
+
IncType(IncType &&) = delete;
|
55 |
+
IncType &operator=(const IncType &) = delete;
|
56 |
+
IncType &operator=(IncType &&) = delete;
|
57 |
+
};
|
58 |
+
|
59 |
+
/// A simple union for basic testing
|
60 |
+
union IntFloat {
|
61 |
+
int i;
|
62 |
+
float f;
|
63 |
+
};
|
64 |
+
|
65 |
+
/// Custom cast-only type that casts to a string "rvalue" or "lvalue" depending on the cast context.
|
66 |
+
/// Used to test recursive casters (e.g. std::tuple, stl containers).
|
67 |
+
struct RValueCaster {};
|
68 |
+
PYBIND11_NAMESPACE_BEGIN(pybind11)
|
69 |
+
PYBIND11_NAMESPACE_BEGIN(detail)
|
70 |
+
template<> class type_caster<RValueCaster> {
|
71 |
+
public:
|
72 |
+
PYBIND11_TYPE_CASTER(RValueCaster, _("RValueCaster"));
|
73 |
+
static handle cast(RValueCaster &&, return_value_policy, handle) { return py::str("rvalue").release(); }
|
74 |
+
static handle cast(const RValueCaster &, return_value_policy, handle) { return py::str("lvalue").release(); }
|
75 |
+
};
|
76 |
+
PYBIND11_NAMESPACE_END(detail)
|
77 |
+
PYBIND11_NAMESPACE_END(pybind11)
|
78 |
+
|
79 |
+
template <typename F>
|
80 |
+
void ignoreOldStyleInitWarnings(F &&body) {
|
81 |
+
py::exec(R"(
|
82 |
+
message = "pybind11-bound class '.+' is using an old-style placement-new '(?:__init__|__setstate__)' which has been deprecated"
|
83 |
+
|
84 |
+
import warnings
|
85 |
+
with warnings.catch_warnings():
|
86 |
+
warnings.filterwarnings("ignore", message=message, category=FutureWarning)
|
87 |
+
body()
|
88 |
+
)", py::dict(py::arg("body") = py::cpp_function(body)));
|
89 |
+
}
|
third-party/DPVO/Pangolin/components/pango_python/pybind11/tests/pytest.ini
ADDED
@@ -0,0 +1,19 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
[pytest]
|
2 |
+
minversion = 3.1
|
3 |
+
norecursedirs = test_* extra_*
|
4 |
+
xfail_strict = True
|
5 |
+
addopts =
|
6 |
+
# show summary of skipped tests
|
7 |
+
-rs
|
8 |
+
# capture only Python print and C++ py::print, but not C output (low-level Python errors)
|
9 |
+
--capture=sys
|
10 |
+
filterwarnings =
|
11 |
+
# make warnings into errors but ignore certain third-party extension issues
|
12 |
+
error
|
13 |
+
# somehow, some DeprecationWarnings do not get turned into errors
|
14 |
+
always::DeprecationWarning
|
15 |
+
# importing scipy submodules on some version of Python
|
16 |
+
ignore::ImportWarning
|
17 |
+
# bogus numpy ABI warning (see numpy/#432)
|
18 |
+
ignore:.*numpy.dtype size changed.*:RuntimeWarning
|
19 |
+
ignore:.*numpy.ufunc size changed.*:RuntimeWarning
|
third-party/DPVO/Pangolin/components/pango_python/pybind11/tests/requirements.txt
ADDED
@@ -0,0 +1,12 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
--extra-index-url https://antocuni.github.io/pypy-wheels/manylinux2010/
|
2 |
+
numpy==1.16.6; python_version<"3.6" and sys_platform!="win32"
|
3 |
+
numpy==1.18.0; platform_python_implementation=="PyPy" and sys_platform=="darwin" and python_version>="3.6"
|
4 |
+
numpy==1.19.3; (platform_python_implementation!="PyPy" or sys_platform=="linux") and python_version=="3.6"
|
5 |
+
numpy==1.20.0; (platform_python_implementation!="PyPy" or sys_platform=="linux") and python_version>="3.7" and python_version<"3.10"
|
6 |
+
pytest==4.6.9; python_version<"3.5"
|
7 |
+
pytest==6.1.2; python_version=="3.5"
|
8 |
+
pytest==6.2.1; python_version>="3.6" and python_version<="3.9"
|
9 |
+
pytest @ git+https://github.com/pytest-dev/pytest@c117bc350ec1e570672fda3b2ad234fd52e72b53; python_version>="3.10"
|
10 |
+
pytest-timeout
|
11 |
+
scipy==1.2.3; (platform_python_implementation!="PyPy" or sys_platform=="linux") and python_version<"3.6"
|
12 |
+
scipy==1.5.4; (platform_python_implementation!="PyPy" or sys_platform=="linux") and python_version>="3.6" and python_version<"3.10"
|
third-party/DPVO/Pangolin/components/pango_python/pybind11/tests/test_async.cpp
ADDED
@@ -0,0 +1,26 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/*
|
2 |
+
tests/test_async.cpp -- __await__ support
|
3 |
+
|
4 |
+
Copyright (c) 2019 Google Inc.
|
5 |
+
|
6 |
+
All rights reserved. Use of this source code is governed by a
|
7 |
+
BSD-style license that can be found in the LICENSE file.
|
8 |
+
*/
|
9 |
+
|
10 |
+
#include "pybind11_tests.h"
|
11 |
+
|
12 |
+
TEST_SUBMODULE(async_module, m) {
|
13 |
+
struct DoesNotSupportAsync {};
|
14 |
+
py::class_<DoesNotSupportAsync>(m, "DoesNotSupportAsync")
|
15 |
+
.def(py::init<>());
|
16 |
+
struct SupportsAsync {};
|
17 |
+
py::class_<SupportsAsync>(m, "SupportsAsync")
|
18 |
+
.def(py::init<>())
|
19 |
+
.def("__await__", [](const SupportsAsync& self) -> py::object {
|
20 |
+
static_cast<void>(self);
|
21 |
+
py::object loop = py::module_::import("asyncio.events").attr("get_event_loop")();
|
22 |
+
py::object f = loop.attr("create_future")();
|
23 |
+
f.attr("set_result")(5);
|
24 |
+
return f.attr("__await__")();
|
25 |
+
});
|
26 |
+
}
|
third-party/DPVO/Pangolin/components/pango_python/pybind11/tests/test_async.py
ADDED
@@ -0,0 +1,25 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# -*- coding: utf-8 -*-
|
2 |
+
import pytest
|
3 |
+
|
4 |
+
asyncio = pytest.importorskip("asyncio")
|
5 |
+
m = pytest.importorskip("pybind11_tests.async_module")
|
6 |
+
|
7 |
+
|
8 |
+
@pytest.fixture
|
9 |
+
def event_loop():
|
10 |
+
loop = asyncio.new_event_loop()
|
11 |
+
yield loop
|
12 |
+
loop.close()
|
13 |
+
|
14 |
+
|
15 |
+
async def get_await_result(x):
|
16 |
+
return await x
|
17 |
+
|
18 |
+
|
19 |
+
def test_await(event_loop):
|
20 |
+
assert 5 == event_loop.run_until_complete(get_await_result(m.SupportsAsync()))
|
21 |
+
|
22 |
+
|
23 |
+
def test_await_missing(event_loop):
|
24 |
+
with pytest.raises(TypeError):
|
25 |
+
event_loop.run_until_complete(get_await_result(m.DoesNotSupportAsync()))
|