Spaces:
Sleeping
Sleeping
970d35941313771ebaf2f6d7f6c9bd1d96d8cdcbc0fdaef7295715b4a06cc1bc
Browse files- third-party/DPVO/DPViewer/pybind11/LICENSE +29 -0
- third-party/DPVO/DPViewer/pybind11/MANIFEST.in +5 -0
- third-party/DPVO/DPViewer/pybind11/README.rst +180 -0
- third-party/DPVO/DPViewer/pybind11/include/pybind11/embed.h +253 -0
- third-party/DPVO/DPViewer/pybind11/include/pybind11/eval.h +156 -0
- third-party/DPVO/DPViewer/pybind11/include/pybind11/functional.h +130 -0
- third-party/DPVO/DPViewer/pybind11/include/pybind11/gil.h +202 -0
- third-party/DPVO/DPViewer/pybind11/include/pybind11/iostream.h +265 -0
- third-party/DPVO/DPViewer/pybind11/include/pybind11/numpy.h +1984 -0
- third-party/DPVO/DPViewer/pybind11/include/pybind11/operators.h +201 -0
- third-party/DPVO/DPViewer/pybind11/include/pybind11/options.h +76 -0
- third-party/DPVO/DPViewer/pybind11/include/pybind11/pybind11.h +0 -0
- third-party/DPVO/DPViewer/pybind11/include/pybind11/pytypes.h +2373 -0
- third-party/DPVO/DPViewer/pybind11/include/pybind11/stl.h +425 -0
- third-party/DPVO/DPViewer/pybind11/include/pybind11/stl/filesystem.h +116 -0
- third-party/DPVO/DPViewer/pybind11/include/pybind11/stl_bind.h +785 -0
- third-party/DPVO/DPViewer/pybind11/noxfile.py +97 -0
- third-party/DPVO/DPViewer/pybind11/pybind11/__init__.py +16 -0
- third-party/DPVO/DPViewer/pybind11/pybind11/__main__.py +49 -0
- third-party/DPVO/DPViewer/pybind11/pybind11/_version.py +12 -0
- third-party/DPVO/DPViewer/pybind11/pybind11/commands.py +25 -0
- third-party/DPVO/DPViewer/pybind11/pybind11/py.typed +0 -0
- third-party/DPVO/DPViewer/pybind11/pybind11/setup_helpers.py +504 -0
- third-party/DPVO/DPViewer/pybind11/pyproject.toml +61 -0
- third-party/DPVO/DPViewer/pybind11/setup.cfg +49 -0
- third-party/DPVO/DPViewer/pybind11/setup.py +149 -0
- third-party/DPVO/DPViewer/pybind11/tools/FindCatch.cmake +72 -0
- third-party/DPVO/DPViewer/pybind11/tools/FindEigen3.cmake +86 -0
- third-party/DPVO/DPViewer/pybind11/tools/FindPythonLibsNew.cmake +281 -0
- third-party/DPVO/DPViewer/pybind11/tools/check-style.sh +44 -0
- third-party/DPVO/DPViewer/pybind11/tools/cmake_uninstall.cmake.in +23 -0
- third-party/DPVO/DPViewer/pybind11/tools/libsize.py +36 -0
- third-party/DPVO/DPViewer/pybind11/tools/make_changelog.py +63 -0
- third-party/DPVO/DPViewer/pybind11/tools/pybind11Common.cmake +385 -0
- third-party/DPVO/DPViewer/pybind11/tools/pybind11Config.cmake.in +231 -0
- third-party/DPVO/DPViewer/pybind11/tools/pybind11NewTools.cmake +254 -0
- third-party/DPVO/DPViewer/pybind11/tools/pybind11Tools.cmake +227 -0
- third-party/DPVO/DPViewer/pybind11/tools/pyproject.toml +3 -0
- third-party/DPVO/DPViewer/pybind11/tools/setup_global.py.in +59 -0
- third-party/DPVO/DPViewer/pybind11/tools/setup_main.py.in +40 -0
- third-party/DPVO/DPViewer/setup.py +132 -0
- third-party/DPVO/dpvo/__init__.py +0 -0
- third-party/DPVO/dpvo/altcorr/__init__.py +1 -0
- third-party/DPVO/dpvo/altcorr/correlation.cpp +63 -0
- third-party/DPVO/dpvo/altcorr/correlation.py +74 -0
- third-party/DPVO/dpvo/altcorr/correlation_kernel.cu +333 -0
- third-party/DPVO/dpvo/ba.py +182 -0
- third-party/DPVO/dpvo/blocks.py +118 -0
- third-party/DPVO/dpvo/config.py +38 -0
- third-party/DPVO/dpvo/data_readers/__init__.py +1 -0
third-party/DPVO/DPViewer/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/DPViewer/pybind11/MANIFEST.in
ADDED
@@ -0,0 +1,5 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
recursive-include pybind11/include/pybind11 *.h
|
2 |
+
recursive-include pybind11 *.py
|
3 |
+
recursive-include pybind11 py.typed
|
4 |
+
include pybind11/share/cmake/pybind11/*.cmake
|
5 |
+
include LICENSE README.rst pyproject.toml setup.py setup.cfg
|
third-party/DPVO/DPViewer/pybind11/README.rst
ADDED
@@ -0,0 +1,180 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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| |GitHub Discussions| |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 (3.6+, 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 3.6+, and PyPy3 7.3 are supported with an implementation-agnostic
|
82 |
+
interface (pybind11 2.9 was the last version to support Python 2 and 3.5).
|
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 <https://graylab.jhu.edu/Sergey/2016.RosettaCon/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 2017 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, Aaron Gokaslan, 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/
|
179 |
+
.. |GitHub Discussions| image:: https://img.shields.io/static/v1?label=Discussions&message=Ask&color=blue&logo=github
|
180 |
+
:target: https://github.com/pybind/pybind11/discussions
|
third-party/DPVO/DPViewer/pybind11/include/pybind11/embed.h
ADDED
@@ -0,0 +1,253 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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 |
+
#include <memory>
|
16 |
+
#include <vector>
|
17 |
+
|
18 |
+
#if defined(PYPY_VERSION)
|
19 |
+
# error Embedding the interpreter is not supported with PyPy
|
20 |
+
#endif
|
21 |
+
|
22 |
+
#define PYBIND11_EMBEDDED_MODULE_IMPL(name) \
|
23 |
+
extern "C" PyObject *pybind11_init_impl_##name(); \
|
24 |
+
extern "C" PyObject *pybind11_init_impl_##name() { return pybind11_init_wrapper_##name(); }
|
25 |
+
|
26 |
+
/** \rst
|
27 |
+
Add a new module to the table of builtins for the interpreter. Must be
|
28 |
+
defined in global scope. The first macro parameter is the name of the
|
29 |
+
module (without quotes). The second parameter is the variable which will
|
30 |
+
be used as the interface to add functions and classes to the module.
|
31 |
+
|
32 |
+
.. code-block:: cpp
|
33 |
+
|
34 |
+
PYBIND11_EMBEDDED_MODULE(example, m) {
|
35 |
+
// ... initialize functions and classes here
|
36 |
+
m.def("foo", []() {
|
37 |
+
return "Hello, World!";
|
38 |
+
});
|
39 |
+
}
|
40 |
+
\endrst */
|
41 |
+
#define PYBIND11_EMBEDDED_MODULE(name, variable) \
|
42 |
+
static ::pybind11::module_::module_def PYBIND11_CONCAT(pybind11_module_def_, name); \
|
43 |
+
static void PYBIND11_CONCAT(pybind11_init_, name)(::pybind11::module_ &); \
|
44 |
+
static PyObject PYBIND11_CONCAT(*pybind11_init_wrapper_, name)() { \
|
45 |
+
auto m = ::pybind11::module_::create_extension_module( \
|
46 |
+
PYBIND11_TOSTRING(name), nullptr, &PYBIND11_CONCAT(pybind11_module_def_, name)); \
|
47 |
+
try { \
|
48 |
+
PYBIND11_CONCAT(pybind11_init_, name)(m); \
|
49 |
+
return m.ptr(); \
|
50 |
+
} \
|
51 |
+
PYBIND11_CATCH_INIT_EXCEPTIONS \
|
52 |
+
} \
|
53 |
+
PYBIND11_EMBEDDED_MODULE_IMPL(name) \
|
54 |
+
::pybind11::detail::embedded_module PYBIND11_CONCAT(pybind11_module_, name)( \
|
55 |
+
PYBIND11_TOSTRING(name), PYBIND11_CONCAT(pybind11_init_impl_, name)); \
|
56 |
+
void PYBIND11_CONCAT(pybind11_init_, name)(::pybind11::module_ \
|
57 |
+
& variable) // NOLINT(bugprone-macro-parentheses)
|
58 |
+
|
59 |
+
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
|
60 |
+
PYBIND11_NAMESPACE_BEGIN(detail)
|
61 |
+
|
62 |
+
/// Python 2.7/3.x compatible version of `PyImport_AppendInittab` and error checks.
|
63 |
+
struct embedded_module {
|
64 |
+
using init_t = PyObject *(*) ();
|
65 |
+
embedded_module(const char *name, init_t init) {
|
66 |
+
if (Py_IsInitialized() != 0) {
|
67 |
+
pybind11_fail("Can't add new modules after the interpreter has been initialized");
|
68 |
+
}
|
69 |
+
|
70 |
+
auto result = PyImport_AppendInittab(name, init);
|
71 |
+
if (result == -1) {
|
72 |
+
pybind11_fail("Insufficient memory to add a new module");
|
73 |
+
}
|
74 |
+
}
|
75 |
+
};
|
76 |
+
|
77 |
+
struct wide_char_arg_deleter {
|
78 |
+
void operator()(wchar_t *ptr) const {
|
79 |
+
// API docs: https://docs.python.org/3/c-api/sys.html#c.Py_DecodeLocale
|
80 |
+
PyMem_RawFree(ptr);
|
81 |
+
}
|
82 |
+
};
|
83 |
+
|
84 |
+
inline wchar_t *widen_chars(const char *safe_arg) {
|
85 |
+
wchar_t *widened_arg = Py_DecodeLocale(safe_arg, nullptr);
|
86 |
+
return widened_arg;
|
87 |
+
}
|
88 |
+
|
89 |
+
/// Python 2.x/3.x-compatible version of `PySys_SetArgv`
|
90 |
+
inline void set_interpreter_argv(int argc, const char *const *argv, bool add_program_dir_to_path) {
|
91 |
+
// Before it was special-cased in python 3.8, passing an empty or null argv
|
92 |
+
// caused a segfault, so we have to reimplement the special case ourselves.
|
93 |
+
bool special_case = (argv == nullptr || argc <= 0);
|
94 |
+
|
95 |
+
const char *const empty_argv[]{"\0"};
|
96 |
+
const char *const *safe_argv = special_case ? empty_argv : argv;
|
97 |
+
if (special_case) {
|
98 |
+
argc = 1;
|
99 |
+
}
|
100 |
+
|
101 |
+
auto argv_size = static_cast<size_t>(argc);
|
102 |
+
// SetArgv* on python 3 takes wchar_t, so we have to convert.
|
103 |
+
std::unique_ptr<wchar_t *[]> widened_argv(new wchar_t *[argv_size]);
|
104 |
+
std::vector<std::unique_ptr<wchar_t[], wide_char_arg_deleter>> widened_argv_entries;
|
105 |
+
widened_argv_entries.reserve(argv_size);
|
106 |
+
for (size_t ii = 0; ii < argv_size; ++ii) {
|
107 |
+
widened_argv_entries.emplace_back(widen_chars(safe_argv[ii]));
|
108 |
+
if (!widened_argv_entries.back()) {
|
109 |
+
// A null here indicates a character-encoding failure or the python
|
110 |
+
// interpreter out of memory. Give up.
|
111 |
+
return;
|
112 |
+
}
|
113 |
+
widened_argv[ii] = widened_argv_entries.back().get();
|
114 |
+
}
|
115 |
+
|
116 |
+
auto *pysys_argv = widened_argv.get();
|
117 |
+
PySys_SetArgvEx(argc, pysys_argv, static_cast<int>(add_program_dir_to_path));
|
118 |
+
}
|
119 |
+
|
120 |
+
PYBIND11_NAMESPACE_END(detail)
|
121 |
+
|
122 |
+
/** \rst
|
123 |
+
Initialize the Python interpreter. No other pybind11 or CPython API functions can be
|
124 |
+
called before this is done; with the exception of `PYBIND11_EMBEDDED_MODULE`. The
|
125 |
+
optional `init_signal_handlers` parameter can be used to skip the registration of
|
126 |
+
signal handlers (see the `Python documentation`_ for details). Calling this function
|
127 |
+
again after the interpreter has already been initialized is a fatal error.
|
128 |
+
|
129 |
+
If initializing the Python interpreter fails, then the program is terminated. (This
|
130 |
+
is controlled by the CPython runtime and is an exception to pybind11's normal behavior
|
131 |
+
of throwing exceptions on errors.)
|
132 |
+
|
133 |
+
The remaining optional parameters, `argc`, `argv`, and `add_program_dir_to_path` are
|
134 |
+
used to populate ``sys.argv`` and ``sys.path``.
|
135 |
+
See the |PySys_SetArgvEx documentation|_ for details.
|
136 |
+
|
137 |
+
.. _Python documentation: https://docs.python.org/3/c-api/init.html#c.Py_InitializeEx
|
138 |
+
.. |PySys_SetArgvEx documentation| replace:: ``PySys_SetArgvEx`` documentation
|
139 |
+
.. _PySys_SetArgvEx documentation: https://docs.python.org/3/c-api/init.html#c.PySys_SetArgvEx
|
140 |
+
\endrst */
|
141 |
+
inline void initialize_interpreter(bool init_signal_handlers = true,
|
142 |
+
int argc = 0,
|
143 |
+
const char *const *argv = nullptr,
|
144 |
+
bool add_program_dir_to_path = true) {
|
145 |
+
if (Py_IsInitialized() != 0) {
|
146 |
+
pybind11_fail("The interpreter is already running");
|
147 |
+
}
|
148 |
+
|
149 |
+
Py_InitializeEx(init_signal_handlers ? 1 : 0);
|
150 |
+
|
151 |
+
detail::set_interpreter_argv(argc, argv, add_program_dir_to_path);
|
152 |
+
}
|
153 |
+
|
154 |
+
/** \rst
|
155 |
+
Shut down the Python interpreter. No pybind11 or CPython API functions can be called
|
156 |
+
after this. In addition, pybind11 objects must not outlive the interpreter:
|
157 |
+
|
158 |
+
.. code-block:: cpp
|
159 |
+
|
160 |
+
{ // BAD
|
161 |
+
py::initialize_interpreter();
|
162 |
+
auto hello = py::str("Hello, World!");
|
163 |
+
py::finalize_interpreter();
|
164 |
+
} // <-- BOOM, hello's destructor is called after interpreter shutdown
|
165 |
+
|
166 |
+
{ // GOOD
|
167 |
+
py::initialize_interpreter();
|
168 |
+
{ // scoped
|
169 |
+
auto hello = py::str("Hello, World!");
|
170 |
+
} // <-- OK, hello is cleaned up properly
|
171 |
+
py::finalize_interpreter();
|
172 |
+
}
|
173 |
+
|
174 |
+
{ // BETTER
|
175 |
+
py::scoped_interpreter guard{};
|
176 |
+
auto hello = py::str("Hello, World!");
|
177 |
+
}
|
178 |
+
|
179 |
+
.. warning::
|
180 |
+
|
181 |
+
The interpreter can be restarted by calling `initialize_interpreter` again.
|
182 |
+
Modules created using pybind11 can be safely re-initialized. However, Python
|
183 |
+
itself cannot completely unload binary extension modules and there are several
|
184 |
+
caveats with regard to interpreter restarting. All the details can be found
|
185 |
+
in the CPython documentation. In short, not all interpreter memory may be
|
186 |
+
freed, either due to reference cycles or user-created global data.
|
187 |
+
|
188 |
+
\endrst */
|
189 |
+
inline void finalize_interpreter() {
|
190 |
+
handle builtins(PyEval_GetBuiltins());
|
191 |
+
const char *id = PYBIND11_INTERNALS_ID;
|
192 |
+
|
193 |
+
// Get the internals pointer (without creating it if it doesn't exist). It's possible for the
|
194 |
+
// internals to be created during Py_Finalize() (e.g. if a py::capsule calls `get_internals()`
|
195 |
+
// during destruction), so we get the pointer-pointer here and check it after Py_Finalize().
|
196 |
+
detail::internals **internals_ptr_ptr = detail::get_internals_pp();
|
197 |
+
// It could also be stashed in builtins, so look there too:
|
198 |
+
if (builtins.contains(id) && isinstance<capsule>(builtins[id])) {
|
199 |
+
internals_ptr_ptr = capsule(builtins[id]);
|
200 |
+
}
|
201 |
+
// Local internals contains data managed by the current interpreter, so we must clear them to
|
202 |
+
// avoid undefined behaviors when initializing another interpreter
|
203 |
+
detail::get_local_internals().registered_types_cpp.clear();
|
204 |
+
detail::get_local_internals().registered_exception_translators.clear();
|
205 |
+
|
206 |
+
Py_Finalize();
|
207 |
+
|
208 |
+
if (internals_ptr_ptr) {
|
209 |
+
delete *internals_ptr_ptr;
|
210 |
+
*internals_ptr_ptr = nullptr;
|
211 |
+
}
|
212 |
+
}
|
213 |
+
|
214 |
+
/** \rst
|
215 |
+
Scope guard version of `initialize_interpreter` and `finalize_interpreter`.
|
216 |
+
This a move-only guard and only a single instance can exist.
|
217 |
+
|
218 |
+
See `initialize_interpreter` for a discussion of its constructor arguments.
|
219 |
+
|
220 |
+
.. code-block:: cpp
|
221 |
+
|
222 |
+
#include <pybind11/embed.h>
|
223 |
+
|
224 |
+
int main() {
|
225 |
+
py::scoped_interpreter guard{};
|
226 |
+
py::print(Hello, World!);
|
227 |
+
} // <-- interpreter shutdown
|
228 |
+
\endrst */
|
229 |
+
class scoped_interpreter {
|
230 |
+
public:
|
231 |
+
explicit scoped_interpreter(bool init_signal_handlers = true,
|
232 |
+
int argc = 0,
|
233 |
+
const char *const *argv = nullptr,
|
234 |
+
bool add_program_dir_to_path = true) {
|
235 |
+
initialize_interpreter(init_signal_handlers, argc, argv, add_program_dir_to_path);
|
236 |
+
}
|
237 |
+
|
238 |
+
scoped_interpreter(const scoped_interpreter &) = delete;
|
239 |
+
scoped_interpreter(scoped_interpreter &&other) noexcept { other.is_valid = false; }
|
240 |
+
scoped_interpreter &operator=(const scoped_interpreter &) = delete;
|
241 |
+
scoped_interpreter &operator=(scoped_interpreter &&) = delete;
|
242 |
+
|
243 |
+
~scoped_interpreter() {
|
244 |
+
if (is_valid) {
|
245 |
+
finalize_interpreter();
|
246 |
+
}
|
247 |
+
}
|
248 |
+
|
249 |
+
private:
|
250 |
+
bool is_valid = true;
|
251 |
+
};
|
252 |
+
|
253 |
+
PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)
|
third-party/DPVO/DPViewer/pybind11/include/pybind11/eval.h
ADDED
@@ -0,0 +1,156 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/*
|
2 |
+
pybind11/eval.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 "pybind11.h"
|
15 |
+
|
16 |
+
#include <utility>
|
17 |
+
|
18 |
+
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
|
19 |
+
PYBIND11_NAMESPACE_BEGIN(detail)
|
20 |
+
|
21 |
+
inline void ensure_builtins_in_globals(object &global) {
|
22 |
+
#if defined(PYPY_VERSION) || PY_VERSION_HEX < 0x03080000
|
23 |
+
// Running exec and eval adds `builtins` module under `__builtins__` key to
|
24 |
+
// globals if not yet present. Python 3.8 made PyRun_String behave
|
25 |
+
// similarly. Let's also do that for older versions, for consistency. This
|
26 |
+
// was missing from PyPy3.8 7.3.7.
|
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 |
+
|
53 |
+
detail::ensure_builtins_in_globals(global);
|
54 |
+
|
55 |
+
/* PyRun_String does not accept a PyObject / encoding specifier,
|
56 |
+
this seems to be the only alternative */
|
57 |
+
std::string buffer = "# -*- coding: utf-8 -*-\n" + (std::string) expr;
|
58 |
+
|
59 |
+
int start = 0;
|
60 |
+
switch (mode) {
|
61 |
+
case eval_expr:
|
62 |
+
start = Py_eval_input;
|
63 |
+
break;
|
64 |
+
case eval_single_statement:
|
65 |
+
start = Py_single_input;
|
66 |
+
break;
|
67 |
+
case eval_statements:
|
68 |
+
start = Py_file_input;
|
69 |
+
break;
|
70 |
+
default:
|
71 |
+
pybind11_fail("invalid evaluation mode");
|
72 |
+
}
|
73 |
+
|
74 |
+
PyObject *result = PyRun_String(buffer.c_str(), start, global.ptr(), local.ptr());
|
75 |
+
if (!result) {
|
76 |
+
throw error_already_set();
|
77 |
+
}
|
78 |
+
return reinterpret_steal<object>(result);
|
79 |
+
}
|
80 |
+
|
81 |
+
template <eval_mode mode = eval_expr, size_t N>
|
82 |
+
object eval(const char (&s)[N], object global = globals(), object local = object()) {
|
83 |
+
/* Support raw string literals by removing common leading whitespace */
|
84 |
+
auto expr = (s[0] == '\n') ? str(module_::import("textwrap").attr("dedent")(s)) : str(s);
|
85 |
+
return eval<mode>(expr, std::move(global), std::move(local));
|
86 |
+
}
|
87 |
+
|
88 |
+
inline void exec(const str &expr, object global = globals(), object local = object()) {
|
89 |
+
eval<eval_statements>(expr, std::move(global), std::move(local));
|
90 |
+
}
|
91 |
+
|
92 |
+
template <size_t N>
|
93 |
+
void exec(const char (&s)[N], object global = globals(), object local = object()) {
|
94 |
+
eval<eval_statements>(s, std::move(global), std::move(local));
|
95 |
+
}
|
96 |
+
|
97 |
+
#if defined(PYPY_VERSION)
|
98 |
+
template <eval_mode mode = eval_statements>
|
99 |
+
object eval_file(str, object, object) {
|
100 |
+
pybind11_fail("eval_file not supported in PyPy3. Use eval");
|
101 |
+
}
|
102 |
+
template <eval_mode mode = eval_statements>
|
103 |
+
object eval_file(str, object) {
|
104 |
+
pybind11_fail("eval_file not supported in PyPy3. Use eval");
|
105 |
+
}
|
106 |
+
template <eval_mode mode = eval_statements>
|
107 |
+
object eval_file(str) {
|
108 |
+
pybind11_fail("eval_file not supported in PyPy3. Use eval");
|
109 |
+
}
|
110 |
+
#else
|
111 |
+
template <eval_mode mode = eval_statements>
|
112 |
+
object eval_file(str fname, object global = globals(), object local = object()) {
|
113 |
+
if (!local) {
|
114 |
+
local = global;
|
115 |
+
}
|
116 |
+
|
117 |
+
detail::ensure_builtins_in_globals(global);
|
118 |
+
|
119 |
+
int start = 0;
|
120 |
+
switch (mode) {
|
121 |
+
case eval_expr:
|
122 |
+
start = Py_eval_input;
|
123 |
+
break;
|
124 |
+
case eval_single_statement:
|
125 |
+
start = Py_single_input;
|
126 |
+
break;
|
127 |
+
case eval_statements:
|
128 |
+
start = Py_file_input;
|
129 |
+
break;
|
130 |
+
default:
|
131 |
+
pybind11_fail("invalid evaluation mode");
|
132 |
+
}
|
133 |
+
|
134 |
+
int closeFile = 1;
|
135 |
+
std::string fname_str = (std::string) fname;
|
136 |
+
FILE *f = _Py_fopen_obj(fname.ptr(), "r");
|
137 |
+
if (!f) {
|
138 |
+
PyErr_Clear();
|
139 |
+
pybind11_fail("File \"" + fname_str + "\" could not be opened!");
|
140 |
+
}
|
141 |
+
|
142 |
+
if (!global.contains("__file__")) {
|
143 |
+
global["__file__"] = std::move(fname);
|
144 |
+
}
|
145 |
+
|
146 |
+
PyObject *result
|
147 |
+
= PyRun_FileEx(f, fname_str.c_str(), start, global.ptr(), local.ptr(), closeFile);
|
148 |
+
|
149 |
+
if (!result) {
|
150 |
+
throw error_already_set();
|
151 |
+
}
|
152 |
+
return reinterpret_steal<object>(result);
|
153 |
+
}
|
154 |
+
#endif
|
155 |
+
|
156 |
+
PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)
|
third-party/DPVO/DPViewer/pybind11/include/pybind11/functional.h
ADDED
@@ -0,0 +1,130 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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 |
+
|
14 |
+
#include <functional>
|
15 |
+
|
16 |
+
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
|
17 |
+
PYBIND11_NAMESPACE_BEGIN(detail)
|
18 |
+
|
19 |
+
template <typename Return, typename... Args>
|
20 |
+
struct type_caster<std::function<Return(Args...)>> {
|
21 |
+
using type = std::function<Return(Args...)>;
|
22 |
+
using retval_type = conditional_t<std::is_same<Return, void>::value, void_type, Return>;
|
23 |
+
using function_type = Return (*)(Args...);
|
24 |
+
|
25 |
+
public:
|
26 |
+
bool load(handle src, bool convert) {
|
27 |
+
if (src.is_none()) {
|
28 |
+
// Defer accepting None to other overloads (if we aren't in convert mode):
|
29 |
+
if (!convert) {
|
30 |
+
return false;
|
31 |
+
}
|
32 |
+
return true;
|
33 |
+
}
|
34 |
+
|
35 |
+
if (!isinstance<function>(src)) {
|
36 |
+
return false;
|
37 |
+
}
|
38 |
+
|
39 |
+
auto func = reinterpret_borrow<function>(src);
|
40 |
+
|
41 |
+
/*
|
42 |
+
When passing a C++ function as an argument to another C++
|
43 |
+
function via Python, every function call would normally involve
|
44 |
+
a full C++ -> Python -> C++ roundtrip, which can be prohibitive.
|
45 |
+
Here, we try to at least detect the case where the function is
|
46 |
+
stateless (i.e. function pointer or lambda function without
|
47 |
+
captured variables), in which case the roundtrip can be avoided.
|
48 |
+
*/
|
49 |
+
if (auto cfunc = func.cpp_function()) {
|
50 |
+
auto *cfunc_self = PyCFunction_GET_SELF(cfunc.ptr());
|
51 |
+
if (isinstance<capsule>(cfunc_self)) {
|
52 |
+
auto c = reinterpret_borrow<capsule>(cfunc_self);
|
53 |
+
auto *rec = (function_record *) c;
|
54 |
+
|
55 |
+
while (rec != nullptr) {
|
56 |
+
if (rec->is_stateless
|
57 |
+
&& same_type(typeid(function_type),
|
58 |
+
*reinterpret_cast<const std::type_info *>(rec->data[1]))) {
|
59 |
+
struct capture {
|
60 |
+
function_type f;
|
61 |
+
};
|
62 |
+
value = ((capture *) &rec->data)->f;
|
63 |
+
return true;
|
64 |
+
}
|
65 |
+
rec = rec->next;
|
66 |
+
}
|
67 |
+
}
|
68 |
+
// PYPY segfaults here when passing builtin function like sum.
|
69 |
+
// Raising an fail exception here works to prevent the segfault, but only on gcc.
|
70 |
+
// See PR #1413 for full details
|
71 |
+
}
|
72 |
+
|
73 |
+
// ensure GIL is held during functor destruction
|
74 |
+
struct func_handle {
|
75 |
+
function f;
|
76 |
+
#if !(defined(_MSC_VER) && _MSC_VER == 1916 && defined(PYBIND11_CPP17))
|
77 |
+
// This triggers a syntax error under very special conditions (very weird indeed).
|
78 |
+
explicit
|
79 |
+
#endif
|
80 |
+
func_handle(function &&f_) noexcept
|
81 |
+
: f(std::move(f_)) {
|
82 |
+
}
|
83 |
+
func_handle(const func_handle &f_) { operator=(f_); }
|
84 |
+
func_handle &operator=(const func_handle &f_) {
|
85 |
+
gil_scoped_acquire acq;
|
86 |
+
f = f_.f;
|
87 |
+
return *this;
|
88 |
+
}
|
89 |
+
~func_handle() {
|
90 |
+
gil_scoped_acquire acq;
|
91 |
+
function kill_f(std::move(f));
|
92 |
+
}
|
93 |
+
};
|
94 |
+
|
95 |
+
// to emulate 'move initialization capture' in C++11
|
96 |
+
struct func_wrapper {
|
97 |
+
func_handle hfunc;
|
98 |
+
explicit func_wrapper(func_handle &&hf) noexcept : hfunc(std::move(hf)) {}
|
99 |
+
Return operator()(Args... args) const {
|
100 |
+
gil_scoped_acquire acq;
|
101 |
+
// casts the returned object as a rvalue to the return type
|
102 |
+
return hfunc.f(std::forward<Args>(args)...).template cast<Return>();
|
103 |
+
}
|
104 |
+
};
|
105 |
+
|
106 |
+
value = func_wrapper(func_handle(std::move(func)));
|
107 |
+
return true;
|
108 |
+
}
|
109 |
+
|
110 |
+
template <typename Func>
|
111 |
+
static handle cast(Func &&f_, return_value_policy policy, handle /* parent */) {
|
112 |
+
if (!f_) {
|
113 |
+
return none().inc_ref();
|
114 |
+
}
|
115 |
+
|
116 |
+
auto result = f_.template target<function_type>();
|
117 |
+
if (result) {
|
118 |
+
return cpp_function(*result, policy).release();
|
119 |
+
}
|
120 |
+
return cpp_function(std::forward<Func>(f_), policy).release();
|
121 |
+
}
|
122 |
+
|
123 |
+
PYBIND11_TYPE_CASTER(type,
|
124 |
+
const_name("Callable[[") + concat(make_caster<Args>::name...)
|
125 |
+
+ const_name("], ") + make_caster<retval_type>::name
|
126 |
+
+ const_name("]"));
|
127 |
+
};
|
128 |
+
|
129 |
+
PYBIND11_NAMESPACE_END(detail)
|
130 |
+
PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)
|
third-party/DPVO/DPViewer/pybind11/include/pybind11/gil.h
ADDED
@@ -0,0 +1,202 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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 |
+
PYBIND11_NAMESPACE_BEGIN(detail)
|
18 |
+
|
19 |
+
// forward declarations
|
20 |
+
PyThreadState *get_thread_state_unchecked();
|
21 |
+
|
22 |
+
PYBIND11_NAMESPACE_END(detail)
|
23 |
+
|
24 |
+
#if defined(WITH_THREAD) && !defined(PYPY_VERSION)
|
25 |
+
|
26 |
+
/* The functions below essentially reproduce the PyGILState_* API using a RAII
|
27 |
+
* pattern, but there are a few important differences:
|
28 |
+
*
|
29 |
+
* 1. When acquiring the GIL from an non-main thread during the finalization
|
30 |
+
* phase, the GILState API blindly terminates the calling thread, which
|
31 |
+
* is often not what is wanted. This API does not do this.
|
32 |
+
*
|
33 |
+
* 2. The gil_scoped_release function can optionally cut the relationship
|
34 |
+
* of a PyThreadState and its associated thread, which allows moving it to
|
35 |
+
* another thread (this is a fairly rare/advanced use case).
|
36 |
+
*
|
37 |
+
* 3. The reference count of an acquired thread state can be controlled. This
|
38 |
+
* can be handy to prevent cases where callbacks issued from an external
|
39 |
+
* thread would otherwise constantly construct and destroy thread state data
|
40 |
+
* structures.
|
41 |
+
*
|
42 |
+
* See the Python bindings of NanoGUI (http://github.com/wjakob/nanogui) for an
|
43 |
+
* example which uses features 2 and 3 to migrate the Python thread of
|
44 |
+
* execution to another thread (to run the event loop on the original thread,
|
45 |
+
* in this case).
|
46 |
+
*/
|
47 |
+
|
48 |
+
class gil_scoped_acquire {
|
49 |
+
public:
|
50 |
+
PYBIND11_NOINLINE gil_scoped_acquire() {
|
51 |
+
auto &internals = detail::get_internals();
|
52 |
+
tstate = (PyThreadState *) PYBIND11_TLS_GET_VALUE(internals.tstate);
|
53 |
+
|
54 |
+
if (!tstate) {
|
55 |
+
/* Check if the GIL was acquired using the PyGILState_* API instead (e.g. if
|
56 |
+
calling from a Python thread). Since we use a different key, this ensures
|
57 |
+
we don't create a new thread state and deadlock in PyEval_AcquireThread
|
58 |
+
below. Note we don't save this state with internals.tstate, since we don't
|
59 |
+
create it we would fail to clear it (its reference count should be > 0). */
|
60 |
+
tstate = PyGILState_GetThisThreadState();
|
61 |
+
}
|
62 |
+
|
63 |
+
if (!tstate) {
|
64 |
+
tstate = PyThreadState_New(internals.istate);
|
65 |
+
# if defined(PYBIND11_DETAILED_ERROR_MESSAGES)
|
66 |
+
if (!tstate) {
|
67 |
+
pybind11_fail("scoped_acquire: could not create thread state!");
|
68 |
+
}
|
69 |
+
# endif
|
70 |
+
tstate->gilstate_counter = 0;
|
71 |
+
PYBIND11_TLS_REPLACE_VALUE(internals.tstate, tstate);
|
72 |
+
} else {
|
73 |
+
release = detail::get_thread_state_unchecked() != tstate;
|
74 |
+
}
|
75 |
+
|
76 |
+
if (release) {
|
77 |
+
PyEval_AcquireThread(tstate);
|
78 |
+
}
|
79 |
+
|
80 |
+
inc_ref();
|
81 |
+
}
|
82 |
+
|
83 |
+
void inc_ref() { ++tstate->gilstate_counter; }
|
84 |
+
|
85 |
+
PYBIND11_NOINLINE void dec_ref() {
|
86 |
+
--tstate->gilstate_counter;
|
87 |
+
# if defined(PYBIND11_DETAILED_ERROR_MESSAGES)
|
88 |
+
if (detail::get_thread_state_unchecked() != tstate) {
|
89 |
+
pybind11_fail("scoped_acquire::dec_ref(): thread state must be current!");
|
90 |
+
}
|
91 |
+
if (tstate->gilstate_counter < 0) {
|
92 |
+
pybind11_fail("scoped_acquire::dec_ref(): reference count underflow!");
|
93 |
+
}
|
94 |
+
# endif
|
95 |
+
if (tstate->gilstate_counter == 0) {
|
96 |
+
# if defined(PYBIND11_DETAILED_ERROR_MESSAGES)
|
97 |
+
if (!release) {
|
98 |
+
pybind11_fail("scoped_acquire::dec_ref(): internal error!");
|
99 |
+
}
|
100 |
+
# endif
|
101 |
+
PyThreadState_Clear(tstate);
|
102 |
+
if (active) {
|
103 |
+
PyThreadState_DeleteCurrent();
|
104 |
+
}
|
105 |
+
PYBIND11_TLS_DELETE_VALUE(detail::get_internals().tstate);
|
106 |
+
release = false;
|
107 |
+
}
|
108 |
+
}
|
109 |
+
|
110 |
+
/// This method will disable the PyThreadState_DeleteCurrent call and the
|
111 |
+
/// GIL won't be acquired. This method should be used if the interpreter
|
112 |
+
/// could be shutting down when this is called, as thread deletion is not
|
113 |
+
/// allowed during shutdown. Check _Py_IsFinalizing() on Python 3.7+, and
|
114 |
+
/// protect subsequent code.
|
115 |
+
PYBIND11_NOINLINE void disarm() { active = false; }
|
116 |
+
|
117 |
+
PYBIND11_NOINLINE ~gil_scoped_acquire() {
|
118 |
+
dec_ref();
|
119 |
+
if (release) {
|
120 |
+
PyEval_SaveThread();
|
121 |
+
}
|
122 |
+
}
|
123 |
+
|
124 |
+
private:
|
125 |
+
PyThreadState *tstate = nullptr;
|
126 |
+
bool release = true;
|
127 |
+
bool active = true;
|
128 |
+
};
|
129 |
+
|
130 |
+
class gil_scoped_release {
|
131 |
+
public:
|
132 |
+
explicit gil_scoped_release(bool disassoc = false) : disassoc(disassoc) {
|
133 |
+
// `get_internals()` must be called here unconditionally in order to initialize
|
134 |
+
// `internals.tstate` for subsequent `gil_scoped_acquire` calls. Otherwise, an
|
135 |
+
// initialization race could occur as multiple threads try `gil_scoped_acquire`.
|
136 |
+
auto &internals = detail::get_internals();
|
137 |
+
// NOLINTNEXTLINE(cppcoreguidelines-prefer-member-initializer)
|
138 |
+
tstate = PyEval_SaveThread();
|
139 |
+
if (disassoc) {
|
140 |
+
// Python >= 3.7 can remove this, it's an int before 3.7
|
141 |
+
// NOLINTNEXTLINE(readability-qualified-auto)
|
142 |
+
auto key = internals.tstate;
|
143 |
+
PYBIND11_TLS_DELETE_VALUE(key);
|
144 |
+
}
|
145 |
+
}
|
146 |
+
|
147 |
+
/// This method will disable the PyThreadState_DeleteCurrent call and the
|
148 |
+
/// GIL won't be acquired. This method should be used if the interpreter
|
149 |
+
/// could be shutting down when this is called, as thread deletion is not
|
150 |
+
/// allowed during shutdown. Check _Py_IsFinalizing() on Python 3.7+, and
|
151 |
+
/// protect subsequent code.
|
152 |
+
PYBIND11_NOINLINE void disarm() { active = false; }
|
153 |
+
|
154 |
+
~gil_scoped_release() {
|
155 |
+
if (!tstate) {
|
156 |
+
return;
|
157 |
+
}
|
158 |
+
// `PyEval_RestoreThread()` should not be called if runtime is finalizing
|
159 |
+
if (active) {
|
160 |
+
PyEval_RestoreThread(tstate);
|
161 |
+
}
|
162 |
+
if (disassoc) {
|
163 |
+
// Python >= 3.7 can remove this, it's an int before 3.7
|
164 |
+
// NOLINTNEXTLINE(readability-qualified-auto)
|
165 |
+
auto key = detail::get_internals().tstate;
|
166 |
+
PYBIND11_TLS_REPLACE_VALUE(key, tstate);
|
167 |
+
}
|
168 |
+
}
|
169 |
+
|
170 |
+
private:
|
171 |
+
PyThreadState *tstate;
|
172 |
+
bool disassoc;
|
173 |
+
bool active = true;
|
174 |
+
};
|
175 |
+
#elif defined(PYPY_VERSION)
|
176 |
+
class gil_scoped_acquire {
|
177 |
+
PyGILState_STATE state;
|
178 |
+
|
179 |
+
public:
|
180 |
+
gil_scoped_acquire() { state = PyGILState_Ensure(); }
|
181 |
+
~gil_scoped_acquire() { PyGILState_Release(state); }
|
182 |
+
void disarm() {}
|
183 |
+
};
|
184 |
+
|
185 |
+
class gil_scoped_release {
|
186 |
+
PyThreadState *state;
|
187 |
+
|
188 |
+
public:
|
189 |
+
gil_scoped_release() { state = PyEval_SaveThread(); }
|
190 |
+
~gil_scoped_release() { PyEval_RestoreThread(state); }
|
191 |
+
void disarm() {}
|
192 |
+
};
|
193 |
+
#else
|
194 |
+
class gil_scoped_acquire {
|
195 |
+
void disarm() {}
|
196 |
+
};
|
197 |
+
class gil_scoped_release {
|
198 |
+
void disarm() {}
|
199 |
+
};
|
200 |
+
#endif
|
201 |
+
|
202 |
+
PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)
|
third-party/DPVO/DPViewer/pybind11/include/pybind11/iostream.h
ADDED
@@ -0,0 +1,265 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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) { return (static_cast<unsigned char>(c) & 0x80) == 0x00; };
|
62 |
+
auto is_leading = [](char c) { return (static_cast<unsigned char>(c) & 0xC0) == 0xC0; };
|
63 |
+
auto is_leading_2b = [](char c) { return static_cast<unsigned char>(c) <= 0xDF; };
|
64 |
+
auto is_leading_3b = [](char c) { return static_cast<unsigned char>(c) <= 0xEF; };
|
65 |
+
// If the last character is ASCII, there are no incomplete code points
|
66 |
+
if (is_ascii(*rpptr)) {
|
67 |
+
return 0;
|
68 |
+
}
|
69 |
+
// Otherwise, work back from the end of the buffer and find the first
|
70 |
+
// UTF-8 leading byte
|
71 |
+
const auto rpend = rbase - rpptr >= 3 ? rpptr + 3 : rbase;
|
72 |
+
const auto leading = std::find_if(rpptr, rpend, is_leading);
|
73 |
+
if (leading == rbase) {
|
74 |
+
return 0;
|
75 |
+
}
|
76 |
+
const auto dist = static_cast<size_t>(leading - rpptr);
|
77 |
+
size_t remainder = 0;
|
78 |
+
|
79 |
+
if (dist == 0) {
|
80 |
+
remainder = 1; // 1-byte code point is impossible
|
81 |
+
} else if (dist == 1) {
|
82 |
+
remainder = is_leading_2b(*leading) ? 0 : dist + 1;
|
83 |
+
} else if (dist == 2) {
|
84 |
+
remainder = is_leading_3b(*leading) ? 0 : dist + 1;
|
85 |
+
}
|
86 |
+
// else if (dist >= 3), at least 4 bytes before encountering an UTF-8
|
87 |
+
// leading byte, either no remainder or invalid UTF-8.
|
88 |
+
// Invalid UTF-8 will cause an exception later when converting
|
89 |
+
// to a Python string, so that's not handled here.
|
90 |
+
return remainder;
|
91 |
+
}
|
92 |
+
|
93 |
+
// This function must be non-virtual to be called in a destructor.
|
94 |
+
int _sync() {
|
95 |
+
if (pbase() != pptr()) { // If buffer is not empty
|
96 |
+
gil_scoped_acquire tmp;
|
97 |
+
// This subtraction cannot be negative, so dropping the sign.
|
98 |
+
auto size = static_cast<size_t>(pptr() - pbase());
|
99 |
+
size_t remainder = utf8_remainder();
|
100 |
+
|
101 |
+
if (size > remainder) {
|
102 |
+
str line(pbase(), size - remainder);
|
103 |
+
pywrite(std::move(line));
|
104 |
+
pyflush();
|
105 |
+
}
|
106 |
+
|
107 |
+
// Copy the remainder at the end of the buffer to the beginning:
|
108 |
+
if (remainder > 0) {
|
109 |
+
std::memmove(pbase(), pptr() - remainder, remainder);
|
110 |
+
}
|
111 |
+
setp(pbase(), epptr());
|
112 |
+
pbump(static_cast<int>(remainder));
|
113 |
+
}
|
114 |
+
return 0;
|
115 |
+
}
|
116 |
+
|
117 |
+
int sync() override { return _sync(); }
|
118 |
+
|
119 |
+
public:
|
120 |
+
explicit pythonbuf(const object &pyostream, size_t buffer_size = 1024)
|
121 |
+
: buf_size(buffer_size), d_buffer(new char[buf_size]), pywrite(pyostream.attr("write")),
|
122 |
+
pyflush(pyostream.attr("flush")) {
|
123 |
+
setp(d_buffer.get(), d_buffer.get() + buf_size - 1);
|
124 |
+
}
|
125 |
+
|
126 |
+
pythonbuf(pythonbuf &&) = default;
|
127 |
+
|
128 |
+
/// Sync before destroy
|
129 |
+
~pythonbuf() override { _sync(); }
|
130 |
+
};
|
131 |
+
|
132 |
+
PYBIND11_NAMESPACE_END(detail)
|
133 |
+
|
134 |
+
/** \rst
|
135 |
+
This a move-only guard that redirects output.
|
136 |
+
|
137 |
+
.. code-block:: cpp
|
138 |
+
|
139 |
+
#include <pybind11/iostream.h>
|
140 |
+
|
141 |
+
...
|
142 |
+
|
143 |
+
{
|
144 |
+
py::scoped_ostream_redirect output;
|
145 |
+
std::cout << "Hello, World!"; // Python stdout
|
146 |
+
} // <-- return std::cout to normal
|
147 |
+
|
148 |
+
You can explicitly pass the c++ stream and the python object,
|
149 |
+
for example to guard stderr instead.
|
150 |
+
|
151 |
+
.. code-block:: cpp
|
152 |
+
|
153 |
+
{
|
154 |
+
py::scoped_ostream_redirect output{
|
155 |
+
std::cerr, py::module::import("sys").attr("stderr")};
|
156 |
+
std::cout << "Hello, World!";
|
157 |
+
}
|
158 |
+
\endrst */
|
159 |
+
class scoped_ostream_redirect {
|
160 |
+
protected:
|
161 |
+
std::streambuf *old;
|
162 |
+
std::ostream &costream;
|
163 |
+
detail::pythonbuf buffer;
|
164 |
+
|
165 |
+
public:
|
166 |
+
explicit scoped_ostream_redirect(std::ostream &costream = std::cout,
|
167 |
+
const object &pyostream
|
168 |
+
= module_::import("sys").attr("stdout"))
|
169 |
+
: costream(costream), buffer(pyostream) {
|
170 |
+
old = costream.rdbuf(&buffer);
|
171 |
+
}
|
172 |
+
|
173 |
+
~scoped_ostream_redirect() { costream.rdbuf(old); }
|
174 |
+
|
175 |
+
scoped_ostream_redirect(const scoped_ostream_redirect &) = delete;
|
176 |
+
scoped_ostream_redirect(scoped_ostream_redirect &&other) = default;
|
177 |
+
scoped_ostream_redirect &operator=(const scoped_ostream_redirect &) = delete;
|
178 |
+
scoped_ostream_redirect &operator=(scoped_ostream_redirect &&) = delete;
|
179 |
+
};
|
180 |
+
|
181 |
+
/** \rst
|
182 |
+
Like `scoped_ostream_redirect`, but redirects cerr by default. This class
|
183 |
+
is provided primary to make ``py::call_guard`` easier to make.
|
184 |
+
|
185 |
+
.. code-block:: cpp
|
186 |
+
|
187 |
+
m.def("noisy_func", &noisy_func,
|
188 |
+
py::call_guard<scoped_ostream_redirect,
|
189 |
+
scoped_estream_redirect>());
|
190 |
+
|
191 |
+
\endrst */
|
192 |
+
class scoped_estream_redirect : public scoped_ostream_redirect {
|
193 |
+
public:
|
194 |
+
explicit scoped_estream_redirect(std::ostream &costream = std::cerr,
|
195 |
+
const object &pyostream
|
196 |
+
= module_::import("sys").attr("stderr"))
|
197 |
+
: scoped_ostream_redirect(costream, pyostream) {}
|
198 |
+
};
|
199 |
+
|
200 |
+
PYBIND11_NAMESPACE_BEGIN(detail)
|
201 |
+
|
202 |
+
// Class to redirect output as a context manager. C++ backend.
|
203 |
+
class OstreamRedirect {
|
204 |
+
bool do_stdout_;
|
205 |
+
bool do_stderr_;
|
206 |
+
std::unique_ptr<scoped_ostream_redirect> redirect_stdout;
|
207 |
+
std::unique_ptr<scoped_estream_redirect> redirect_stderr;
|
208 |
+
|
209 |
+
public:
|
210 |
+
explicit OstreamRedirect(bool do_stdout = true, bool do_stderr = true)
|
211 |
+
: do_stdout_(do_stdout), do_stderr_(do_stderr) {}
|
212 |
+
|
213 |
+
void enter() {
|
214 |
+
if (do_stdout_) {
|
215 |
+
redirect_stdout.reset(new scoped_ostream_redirect());
|
216 |
+
}
|
217 |
+
if (do_stderr_) {
|
218 |
+
redirect_stderr.reset(new scoped_estream_redirect());
|
219 |
+
}
|
220 |
+
}
|
221 |
+
|
222 |
+
void exit() {
|
223 |
+
redirect_stdout.reset();
|
224 |
+
redirect_stderr.reset();
|
225 |
+
}
|
226 |
+
};
|
227 |
+
|
228 |
+
PYBIND11_NAMESPACE_END(detail)
|
229 |
+
|
230 |
+
/** \rst
|
231 |
+
This is a helper function to add a C++ redirect context manager to Python
|
232 |
+
instead of using a C++ guard. To use it, add the following to your binding code:
|
233 |
+
|
234 |
+
.. code-block:: cpp
|
235 |
+
|
236 |
+
#include <pybind11/iostream.h>
|
237 |
+
|
238 |
+
...
|
239 |
+
|
240 |
+
py::add_ostream_redirect(m, "ostream_redirect");
|
241 |
+
|
242 |
+
You now have a Python context manager that redirects your output:
|
243 |
+
|
244 |
+
.. code-block:: python
|
245 |
+
|
246 |
+
with m.ostream_redirect():
|
247 |
+
m.print_to_cout_function()
|
248 |
+
|
249 |
+
This manager can optionally be told which streams to operate on:
|
250 |
+
|
251 |
+
.. code-block:: python
|
252 |
+
|
253 |
+
with m.ostream_redirect(stdout=true, stderr=true):
|
254 |
+
m.noisy_function_with_error_printing()
|
255 |
+
|
256 |
+
\endrst */
|
257 |
+
inline class_<detail::OstreamRedirect>
|
258 |
+
add_ostream_redirect(module_ m, const std::string &name = "ostream_redirect") {
|
259 |
+
return class_<detail::OstreamRedirect>(std::move(m), name.c_str(), module_local())
|
260 |
+
.def(init<bool, bool>(), arg("stdout") = true, arg("stderr") = true)
|
261 |
+
.def("__enter__", &detail::OstreamRedirect::enter)
|
262 |
+
.def("__exit__", [](detail::OstreamRedirect &self_, const args &) { self_.exit(); });
|
263 |
+
}
|
264 |
+
|
265 |
+
PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)
|
third-party/DPVO/DPViewer/pybind11/include/pybind11/numpy.h
ADDED
@@ -0,0 +1,1984 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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 |
+
|
15 |
+
#include <algorithm>
|
16 |
+
#include <array>
|
17 |
+
#include <cstdint>
|
18 |
+
#include <cstdlib>
|
19 |
+
#include <cstring>
|
20 |
+
#include <functional>
|
21 |
+
#include <numeric>
|
22 |
+
#include <sstream>
|
23 |
+
#include <string>
|
24 |
+
#include <type_traits>
|
25 |
+
#include <typeindex>
|
26 |
+
#include <utility>
|
27 |
+
#include <vector>
|
28 |
+
|
29 |
+
/* This will be true on all flat address space platforms and allows us to reduce the
|
30 |
+
whole npy_intp / ssize_t / Py_intptr_t business down to just ssize_t for all size
|
31 |
+
and dimension types (e.g. shape, strides, indexing), instead of inflicting this
|
32 |
+
upon the library user. */
|
33 |
+
static_assert(sizeof(::pybind11::ssize_t) == sizeof(Py_intptr_t), "ssize_t != Py_intptr_t");
|
34 |
+
static_assert(std::is_signed<Py_intptr_t>::value, "Py_intptr_t must be signed");
|
35 |
+
// We now can reinterpret_cast between py::ssize_t and Py_intptr_t (MSVC + PyPy cares)
|
36 |
+
|
37 |
+
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
|
38 |
+
|
39 |
+
class array; // Forward declaration
|
40 |
+
|
41 |
+
PYBIND11_NAMESPACE_BEGIN(detail)
|
42 |
+
|
43 |
+
template <>
|
44 |
+
struct handle_type_name<array> {
|
45 |
+
static constexpr auto name = const_name("numpy.ndarray");
|
46 |
+
};
|
47 |
+
|
48 |
+
template <typename type, typename SFINAE = void>
|
49 |
+
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 char *obval;
|
79 |
+
PyArrayDescr_Proxy *descr;
|
80 |
+
int flags;
|
81 |
+
PyObject *base;
|
82 |
+
};
|
83 |
+
|
84 |
+
struct numpy_type_info {
|
85 |
+
PyObject *dtype_ptr;
|
86 |
+
std::string format_str;
|
87 |
+
};
|
88 |
+
|
89 |
+
struct numpy_internals {
|
90 |
+
std::unordered_map<std::type_index, numpy_type_info> registered_dtypes;
|
91 |
+
|
92 |
+
numpy_type_info *get_type_info(const std::type_info &tinfo, bool throw_if_missing = true) {
|
93 |
+
auto it = registered_dtypes.find(std::type_index(tinfo));
|
94 |
+
if (it != registered_dtypes.end()) {
|
95 |
+
return &(it->second);
|
96 |
+
}
|
97 |
+
if (throw_if_missing) {
|
98 |
+
pybind11_fail(std::string("NumPy type info missing for ") + tinfo.name());
|
99 |
+
}
|
100 |
+
return nullptr;
|
101 |
+
}
|
102 |
+
|
103 |
+
template <typename T>
|
104 |
+
numpy_type_info *get_type_info(bool throw_if_missing = true) {
|
105 |
+
return get_type_info(typeid(typename std::remove_cv<T>::type), throw_if_missing);
|
106 |
+
}
|
107 |
+
};
|
108 |
+
|
109 |
+
PYBIND11_NOINLINE void load_numpy_internals(numpy_internals *&ptr) {
|
110 |
+
ptr = &get_or_create_shared_data<numpy_internals>("_numpy_internals");
|
111 |
+
}
|
112 |
+
|
113 |
+
inline numpy_internals &get_numpy_internals() {
|
114 |
+
static numpy_internals *ptr = nullptr;
|
115 |
+
if (!ptr) {
|
116 |
+
load_numpy_internals(ptr);
|
117 |
+
}
|
118 |
+
return *ptr;
|
119 |
+
}
|
120 |
+
|
121 |
+
template <typename T>
|
122 |
+
struct same_size {
|
123 |
+
template <typename U>
|
124 |
+
using as = bool_constant<sizeof(T) == sizeof(U)>;
|
125 |
+
};
|
126 |
+
|
127 |
+
template <typename Concrete>
|
128 |
+
constexpr int platform_lookup() {
|
129 |
+
return -1;
|
130 |
+
}
|
131 |
+
|
132 |
+
// Lookup a type according to its size, and return a value corresponding to the NumPy typenum.
|
133 |
+
template <typename Concrete, typename T, typename... Ts, typename... Ints>
|
134 |
+
constexpr int platform_lookup(int I, Ints... Is) {
|
135 |
+
return sizeof(Concrete) == sizeof(T) ? I : platform_lookup<Concrete, Ts...>(Is...);
|
136 |
+
}
|
137 |
+
|
138 |
+
struct npy_api {
|
139 |
+
enum constants {
|
140 |
+
NPY_ARRAY_C_CONTIGUOUS_ = 0x0001,
|
141 |
+
NPY_ARRAY_F_CONTIGUOUS_ = 0x0002,
|
142 |
+
NPY_ARRAY_OWNDATA_ = 0x0004,
|
143 |
+
NPY_ARRAY_FORCECAST_ = 0x0010,
|
144 |
+
NPY_ARRAY_ENSUREARRAY_ = 0x0040,
|
145 |
+
NPY_ARRAY_ALIGNED_ = 0x0100,
|
146 |
+
NPY_ARRAY_WRITEABLE_ = 0x0400,
|
147 |
+
NPY_BOOL_ = 0,
|
148 |
+
NPY_BYTE_,
|
149 |
+
NPY_UBYTE_,
|
150 |
+
NPY_SHORT_,
|
151 |
+
NPY_USHORT_,
|
152 |
+
NPY_INT_,
|
153 |
+
NPY_UINT_,
|
154 |
+
NPY_LONG_,
|
155 |
+
NPY_ULONG_,
|
156 |
+
NPY_LONGLONG_,
|
157 |
+
NPY_ULONGLONG_,
|
158 |
+
NPY_FLOAT_,
|
159 |
+
NPY_DOUBLE_,
|
160 |
+
NPY_LONGDOUBLE_,
|
161 |
+
NPY_CFLOAT_,
|
162 |
+
NPY_CDOUBLE_,
|
163 |
+
NPY_CLONGDOUBLE_,
|
164 |
+
NPY_OBJECT_ = 17,
|
165 |
+
NPY_STRING_,
|
166 |
+
NPY_UNICODE_,
|
167 |
+
NPY_VOID_,
|
168 |
+
// Platform-dependent normalization
|
169 |
+
NPY_INT8_ = NPY_BYTE_,
|
170 |
+
NPY_UINT8_ = NPY_UBYTE_,
|
171 |
+
NPY_INT16_ = NPY_SHORT_,
|
172 |
+
NPY_UINT16_ = NPY_USHORT_,
|
173 |
+
// `npy_common.h` defines the integer aliases. In order, it checks:
|
174 |
+
// NPY_BITSOF_LONG, NPY_BITSOF_LONGLONG, NPY_BITSOF_INT, NPY_BITSOF_SHORT, NPY_BITSOF_CHAR
|
175 |
+
// and assigns the alias to the first matching size, so we should check in this order.
|
176 |
+
NPY_INT32_
|
177 |
+
= platform_lookup<std::int32_t, long, int, short>(NPY_LONG_, NPY_INT_, NPY_SHORT_),
|
178 |
+
NPY_UINT32_ = platform_lookup<std::uint32_t, unsigned long, unsigned int, unsigned short>(
|
179 |
+
NPY_ULONG_, NPY_UINT_, NPY_USHORT_),
|
180 |
+
NPY_INT64_
|
181 |
+
= platform_lookup<std::int64_t, long, long long, int>(NPY_LONG_, NPY_LONGLONG_, NPY_INT_),
|
182 |
+
NPY_UINT64_
|
183 |
+
= platform_lookup<std::uint64_t, unsigned long, unsigned long long, unsigned int>(
|
184 |
+
NPY_ULONG_, NPY_ULONGLONG_, NPY_UINT_),
|
185 |
+
};
|
186 |
+
|
187 |
+
struct PyArray_Dims {
|
188 |
+
Py_intptr_t *ptr;
|
189 |
+
int len;
|
190 |
+
};
|
191 |
+
|
192 |
+
static npy_api &get() {
|
193 |
+
static npy_api api = lookup();
|
194 |
+
return api;
|
195 |
+
}
|
196 |
+
|
197 |
+
bool PyArray_Check_(PyObject *obj) const {
|
198 |
+
return PyObject_TypeCheck(obj, PyArray_Type_) != 0;
|
199 |
+
}
|
200 |
+
bool PyArrayDescr_Check_(PyObject *obj) const {
|
201 |
+
return PyObject_TypeCheck(obj, PyArrayDescr_Type_) != 0;
|
202 |
+
}
|
203 |
+
|
204 |
+
unsigned int (*PyArray_GetNDArrayCFeatureVersion_)();
|
205 |
+
PyObject *(*PyArray_DescrFromType_)(int);
|
206 |
+
PyObject *(*PyArray_NewFromDescr_)(PyTypeObject *,
|
207 |
+
PyObject *,
|
208 |
+
int,
|
209 |
+
Py_intptr_t const *,
|
210 |
+
Py_intptr_t const *,
|
211 |
+
void *,
|
212 |
+
int,
|
213 |
+
PyObject *);
|
214 |
+
// Unused. Not removed because that affects ABI of the class.
|
215 |
+
PyObject *(*PyArray_DescrNewFromType_)(int);
|
216 |
+
int (*PyArray_CopyInto_)(PyObject *, PyObject *);
|
217 |
+
PyObject *(*PyArray_NewCopy_)(PyObject *, int);
|
218 |
+
PyTypeObject *PyArray_Type_;
|
219 |
+
PyTypeObject *PyVoidArrType_Type_;
|
220 |
+
PyTypeObject *PyArrayDescr_Type_;
|
221 |
+
PyObject *(*PyArray_DescrFromScalar_)(PyObject *);
|
222 |
+
PyObject *(*PyArray_FromAny_)(PyObject *, PyObject *, int, int, int, PyObject *);
|
223 |
+
int (*PyArray_DescrConverter_)(PyObject *, PyObject **);
|
224 |
+
bool (*PyArray_EquivTypes_)(PyObject *, PyObject *);
|
225 |
+
int (*PyArray_GetArrayParamsFromObject_)(PyObject *,
|
226 |
+
PyObject *,
|
227 |
+
unsigned char,
|
228 |
+
PyObject **,
|
229 |
+
int *,
|
230 |
+
Py_intptr_t *,
|
231 |
+
PyObject **,
|
232 |
+
PyObject *);
|
233 |
+
PyObject *(*PyArray_Squeeze_)(PyObject *);
|
234 |
+
// Unused. Not removed because that affects ABI of the class.
|
235 |
+
int (*PyArray_SetBaseObject_)(PyObject *, PyObject *);
|
236 |
+
PyObject *(*PyArray_Resize_)(PyObject *, PyArray_Dims *, int, int);
|
237 |
+
PyObject *(*PyArray_Newshape_)(PyObject *, PyArray_Dims *, int);
|
238 |
+
PyObject *(*PyArray_View_)(PyObject *, PyObject *, PyObject *);
|
239 |
+
|
240 |
+
private:
|
241 |
+
enum functions {
|
242 |
+
API_PyArray_GetNDArrayCFeatureVersion = 211,
|
243 |
+
API_PyArray_Type = 2,
|
244 |
+
API_PyArrayDescr_Type = 3,
|
245 |
+
API_PyVoidArrType_Type = 39,
|
246 |
+
API_PyArray_DescrFromType = 45,
|
247 |
+
API_PyArray_DescrFromScalar = 57,
|
248 |
+
API_PyArray_FromAny = 69,
|
249 |
+
API_PyArray_Resize = 80,
|
250 |
+
API_PyArray_CopyInto = 82,
|
251 |
+
API_PyArray_NewCopy = 85,
|
252 |
+
API_PyArray_NewFromDescr = 94,
|
253 |
+
API_PyArray_DescrNewFromType = 96,
|
254 |
+
API_PyArray_Newshape = 135,
|
255 |
+
API_PyArray_Squeeze = 136,
|
256 |
+
API_PyArray_View = 137,
|
257 |
+
API_PyArray_DescrConverter = 174,
|
258 |
+
API_PyArray_EquivTypes = 182,
|
259 |
+
API_PyArray_GetArrayParamsFromObject = 278,
|
260 |
+
API_PyArray_SetBaseObject = 282
|
261 |
+
};
|
262 |
+
|
263 |
+
static npy_api lookup() {
|
264 |
+
module_ m = module_::import("numpy.core.multiarray");
|
265 |
+
auto c = m.attr("_ARRAY_API");
|
266 |
+
void **api_ptr = (void **) PyCapsule_GetPointer(c.ptr(), nullptr);
|
267 |
+
npy_api api;
|
268 |
+
#define DECL_NPY_API(Func) api.Func##_ = (decltype(api.Func##_)) api_ptr[API_##Func];
|
269 |
+
DECL_NPY_API(PyArray_GetNDArrayCFeatureVersion);
|
270 |
+
if (api.PyArray_GetNDArrayCFeatureVersion_() < 0x7) {
|
271 |
+
pybind11_fail("pybind11 numpy support requires numpy >= 1.7.0");
|
272 |
+
}
|
273 |
+
DECL_NPY_API(PyArray_Type);
|
274 |
+
DECL_NPY_API(PyVoidArrType_Type);
|
275 |
+
DECL_NPY_API(PyArrayDescr_Type);
|
276 |
+
DECL_NPY_API(PyArray_DescrFromType);
|
277 |
+
DECL_NPY_API(PyArray_DescrFromScalar);
|
278 |
+
DECL_NPY_API(PyArray_FromAny);
|
279 |
+
DECL_NPY_API(PyArray_Resize);
|
280 |
+
DECL_NPY_API(PyArray_CopyInto);
|
281 |
+
DECL_NPY_API(PyArray_NewCopy);
|
282 |
+
DECL_NPY_API(PyArray_NewFromDescr);
|
283 |
+
DECL_NPY_API(PyArray_DescrNewFromType);
|
284 |
+
DECL_NPY_API(PyArray_Newshape);
|
285 |
+
DECL_NPY_API(PyArray_Squeeze);
|
286 |
+
DECL_NPY_API(PyArray_View);
|
287 |
+
DECL_NPY_API(PyArray_DescrConverter);
|
288 |
+
DECL_NPY_API(PyArray_EquivTypes);
|
289 |
+
DECL_NPY_API(PyArray_GetArrayParamsFromObject);
|
290 |
+
DECL_NPY_API(PyArray_SetBaseObject);
|
291 |
+
|
292 |
+
#undef DECL_NPY_API
|
293 |
+
return api;
|
294 |
+
}
|
295 |
+
};
|
296 |
+
|
297 |
+
inline PyArray_Proxy *array_proxy(void *ptr) { return reinterpret_cast<PyArray_Proxy *>(ptr); }
|
298 |
+
|
299 |
+
inline const PyArray_Proxy *array_proxy(const void *ptr) {
|
300 |
+
return reinterpret_cast<const PyArray_Proxy *>(ptr);
|
301 |
+
}
|
302 |
+
|
303 |
+
inline PyArrayDescr_Proxy *array_descriptor_proxy(PyObject *ptr) {
|
304 |
+
return reinterpret_cast<PyArrayDescr_Proxy *>(ptr);
|
305 |
+
}
|
306 |
+
|
307 |
+
inline const PyArrayDescr_Proxy *array_descriptor_proxy(const PyObject *ptr) {
|
308 |
+
return reinterpret_cast<const PyArrayDescr_Proxy *>(ptr);
|
309 |
+
}
|
310 |
+
|
311 |
+
inline bool check_flags(const void *ptr, int flag) {
|
312 |
+
return (flag == (array_proxy(ptr)->flags & flag));
|
313 |
+
}
|
314 |
+
|
315 |
+
template <typename T>
|
316 |
+
struct is_std_array : std::false_type {};
|
317 |
+
template <typename T, size_t N>
|
318 |
+
struct is_std_array<std::array<T, N>> : std::true_type {};
|
319 |
+
template <typename T>
|
320 |
+
struct is_complex : std::false_type {};
|
321 |
+
template <typename T>
|
322 |
+
struct is_complex<std::complex<T>> : std::true_type {};
|
323 |
+
|
324 |
+
template <typename T>
|
325 |
+
struct array_info_scalar {
|
326 |
+
using type = T;
|
327 |
+
static constexpr bool is_array = false;
|
328 |
+
static constexpr bool is_empty = false;
|
329 |
+
static constexpr auto extents = const_name("");
|
330 |
+
static void append_extents(list & /* shape */) {}
|
331 |
+
};
|
332 |
+
// Computes underlying type and a comma-separated list of extents for array
|
333 |
+
// types (any mix of std::array and built-in arrays). An array of char is
|
334 |
+
// treated as scalar because it gets special handling.
|
335 |
+
template <typename T>
|
336 |
+
struct array_info : array_info_scalar<T> {};
|
337 |
+
template <typename T, size_t N>
|
338 |
+
struct array_info<std::array<T, N>> {
|
339 |
+
using type = typename array_info<T>::type;
|
340 |
+
static constexpr bool is_array = true;
|
341 |
+
static constexpr bool is_empty = (N == 0) || array_info<T>::is_empty;
|
342 |
+
static constexpr size_t extent = N;
|
343 |
+
|
344 |
+
// appends the extents to shape
|
345 |
+
static void append_extents(list &shape) {
|
346 |
+
shape.append(N);
|
347 |
+
array_info<T>::append_extents(shape);
|
348 |
+
}
|
349 |
+
|
350 |
+
static constexpr auto extents = const_name<array_info<T>::is_array>(
|
351 |
+
concat(const_name<N>(), array_info<T>::extents), const_name<N>());
|
352 |
+
};
|
353 |
+
// For numpy we have special handling for arrays of characters, so we don't include
|
354 |
+
// the size in the array extents.
|
355 |
+
template <size_t N>
|
356 |
+
struct array_info<char[N]> : array_info_scalar<char[N]> {};
|
357 |
+
template <size_t N>
|
358 |
+
struct array_info<std::array<char, N>> : array_info_scalar<std::array<char, N>> {};
|
359 |
+
template <typename T, size_t N>
|
360 |
+
struct array_info<T[N]> : array_info<std::array<T, N>> {};
|
361 |
+
template <typename T>
|
362 |
+
using remove_all_extents_t = typename array_info<T>::type;
|
363 |
+
|
364 |
+
template <typename T>
|
365 |
+
using is_pod_struct
|
366 |
+
= all_of<std::is_standard_layout<T>, // since we're accessing directly in memory
|
367 |
+
// we need a standard layout type
|
368 |
+
#if defined(__GLIBCXX__) \
|
369 |
+
&& (__GLIBCXX__ < 20150422 || __GLIBCXX__ == 20150426 || __GLIBCXX__ == 20150623 \
|
370 |
+
|| __GLIBCXX__ == 20150626 || __GLIBCXX__ == 20160803)
|
371 |
+
// libstdc++ < 5 (including versions 4.8.5, 4.9.3 and 4.9.4 which were released after
|
372 |
+
// 5) don't implement is_trivially_copyable, so approximate it
|
373 |
+
std::is_trivially_destructible<T>,
|
374 |
+
satisfies_any_of<T, std::has_trivial_copy_constructor, std::has_trivial_copy_assign>,
|
375 |
+
#else
|
376 |
+
std::is_trivially_copyable<T>,
|
377 |
+
#endif
|
378 |
+
satisfies_none_of<T,
|
379 |
+
std::is_reference,
|
380 |
+
std::is_array,
|
381 |
+
is_std_array,
|
382 |
+
std::is_arithmetic,
|
383 |
+
is_complex,
|
384 |
+
std::is_enum>>;
|
385 |
+
|
386 |
+
// Replacement for std::is_pod (deprecated in C++20)
|
387 |
+
template <typename T>
|
388 |
+
using is_pod = all_of<std::is_standard_layout<T>, std::is_trivial<T>>;
|
389 |
+
|
390 |
+
template <ssize_t Dim = 0, typename Strides>
|
391 |
+
ssize_t byte_offset_unsafe(const Strides &) {
|
392 |
+
return 0;
|
393 |
+
}
|
394 |
+
template <ssize_t Dim = 0, typename Strides, typename... Ix>
|
395 |
+
ssize_t byte_offset_unsafe(const Strides &strides, ssize_t i, Ix... index) {
|
396 |
+
return i * strides[Dim] + byte_offset_unsafe<Dim + 1>(strides, index...);
|
397 |
+
}
|
398 |
+
|
399 |
+
/**
|
400 |
+
* Proxy class providing unsafe, unchecked const access to array data. This is constructed through
|
401 |
+
* the `unchecked<T, N>()` method of `array` or the `unchecked<N>()` method of `array_t<T>`. `Dims`
|
402 |
+
* will be -1 for dimensions determined at runtime.
|
403 |
+
*/
|
404 |
+
template <typename T, ssize_t Dims>
|
405 |
+
class unchecked_reference {
|
406 |
+
protected:
|
407 |
+
static constexpr bool Dynamic = Dims < 0;
|
408 |
+
const unsigned char *data_;
|
409 |
+
// Storing the shape & strides in local variables (i.e. these arrays) allows the compiler to
|
410 |
+
// make large performance gains on big, nested loops, but requires compile-time dimensions
|
411 |
+
conditional_t<Dynamic, const ssize_t *, std::array<ssize_t, (size_t) Dims>> shape_, strides_;
|
412 |
+
const ssize_t dims_;
|
413 |
+
|
414 |
+
friend class pybind11::array;
|
415 |
+
// Constructor for compile-time dimensions:
|
416 |
+
template <bool Dyn = Dynamic>
|
417 |
+
unchecked_reference(const void *data,
|
418 |
+
const ssize_t *shape,
|
419 |
+
const ssize_t *strides,
|
420 |
+
enable_if_t<!Dyn, ssize_t>)
|
421 |
+
: data_{reinterpret_cast<const unsigned char *>(data)}, dims_{Dims} {
|
422 |
+
for (size_t i = 0; i < (size_t) dims_; i++) {
|
423 |
+
shape_[i] = shape[i];
|
424 |
+
strides_[i] = strides[i];
|
425 |
+
}
|
426 |
+
}
|
427 |
+
// Constructor for runtime dimensions:
|
428 |
+
template <bool Dyn = Dynamic>
|
429 |
+
unchecked_reference(const void *data,
|
430 |
+
const ssize_t *shape,
|
431 |
+
const ssize_t *strides,
|
432 |
+
enable_if_t<Dyn, ssize_t> dims)
|
433 |
+
: data_{reinterpret_cast<const unsigned char *>(data)}, shape_{shape}, strides_{strides},
|
434 |
+
dims_{dims} {}
|
435 |
+
|
436 |
+
public:
|
437 |
+
/**
|
438 |
+
* Unchecked const reference access to data at the given indices. For a compile-time known
|
439 |
+
* number of dimensions, this requires the correct number of arguments; for run-time
|
440 |
+
* dimensionality, this is not checked (and so is up to the caller to use safely).
|
441 |
+
*/
|
442 |
+
template <typename... Ix>
|
443 |
+
const T &operator()(Ix... index) const {
|
444 |
+
static_assert(ssize_t{sizeof...(Ix)} == Dims || Dynamic,
|
445 |
+
"Invalid number of indices for unchecked array reference");
|
446 |
+
return *reinterpret_cast<const T *>(data_
|
447 |
+
+ byte_offset_unsafe(strides_, ssize_t(index)...));
|
448 |
+
}
|
449 |
+
/**
|
450 |
+
* Unchecked const reference access to data; this operator only participates if the reference
|
451 |
+
* is to a 1-dimensional array. When present, this is exactly equivalent to `obj(index)`.
|
452 |
+
*/
|
453 |
+
template <ssize_t D = Dims, typename = enable_if_t<D == 1 || Dynamic>>
|
454 |
+
const T &operator[](ssize_t index) const {
|
455 |
+
return operator()(index);
|
456 |
+
}
|
457 |
+
|
458 |
+
/// Pointer access to the data at the given indices.
|
459 |
+
template <typename... Ix>
|
460 |
+
const T *data(Ix... ix) const {
|
461 |
+
return &operator()(ssize_t(ix)...);
|
462 |
+
}
|
463 |
+
|
464 |
+
/// Returns the item size, i.e. sizeof(T)
|
465 |
+
constexpr static ssize_t itemsize() { return sizeof(T); }
|
466 |
+
|
467 |
+
/// Returns the shape (i.e. size) of dimension `dim`
|
468 |
+
ssize_t shape(ssize_t dim) const { return shape_[(size_t) dim]; }
|
469 |
+
|
470 |
+
/// Returns the number of dimensions of the array
|
471 |
+
ssize_t ndim() const { return dims_; }
|
472 |
+
|
473 |
+
/// Returns the total number of elements in the referenced array, i.e. the product of the
|
474 |
+
/// shapes
|
475 |
+
template <bool Dyn = Dynamic>
|
476 |
+
enable_if_t<!Dyn, ssize_t> size() const {
|
477 |
+
return std::accumulate(
|
478 |
+
shape_.begin(), shape_.end(), (ssize_t) 1, std::multiplies<ssize_t>());
|
479 |
+
}
|
480 |
+
template <bool Dyn = Dynamic>
|
481 |
+
enable_if_t<Dyn, ssize_t> size() const {
|
482 |
+
return std::accumulate(shape_, shape_ + ndim(), (ssize_t) 1, std::multiplies<ssize_t>());
|
483 |
+
}
|
484 |
+
|
485 |
+
/// Returns the total number of bytes used by the referenced data. Note that the actual span
|
486 |
+
/// in memory may be larger if the referenced array has non-contiguous strides (e.g. for a
|
487 |
+
/// slice).
|
488 |
+
ssize_t nbytes() const { return size() * itemsize(); }
|
489 |
+
};
|
490 |
+
|
491 |
+
template <typename T, ssize_t Dims>
|
492 |
+
class unchecked_mutable_reference : public unchecked_reference<T, Dims> {
|
493 |
+
friend class pybind11::array;
|
494 |
+
using ConstBase = unchecked_reference<T, Dims>;
|
495 |
+
using ConstBase::ConstBase;
|
496 |
+
using ConstBase::Dynamic;
|
497 |
+
|
498 |
+
public:
|
499 |
+
// Bring in const-qualified versions from base class
|
500 |
+
using ConstBase::operator();
|
501 |
+
using ConstBase::operator[];
|
502 |
+
|
503 |
+
/// Mutable, unchecked access to data at the given indices.
|
504 |
+
template <typename... Ix>
|
505 |
+
T &operator()(Ix... index) {
|
506 |
+
static_assert(ssize_t{sizeof...(Ix)} == Dims || Dynamic,
|
507 |
+
"Invalid number of indices for unchecked array reference");
|
508 |
+
return const_cast<T &>(ConstBase::operator()(index...));
|
509 |
+
}
|
510 |
+
/**
|
511 |
+
* Mutable, unchecked access data at the given index; this operator only participates if the
|
512 |
+
* reference is to a 1-dimensional array (or has runtime dimensions). When present, this is
|
513 |
+
* exactly equivalent to `obj(index)`.
|
514 |
+
*/
|
515 |
+
template <ssize_t D = Dims, typename = enable_if_t<D == 1 || Dynamic>>
|
516 |
+
T &operator[](ssize_t index) {
|
517 |
+
return operator()(index);
|
518 |
+
}
|
519 |
+
|
520 |
+
/// Mutable pointer access to the data at the given indices.
|
521 |
+
template <typename... Ix>
|
522 |
+
T *mutable_data(Ix... ix) {
|
523 |
+
return &operator()(ssize_t(ix)...);
|
524 |
+
}
|
525 |
+
};
|
526 |
+
|
527 |
+
template <typename T, ssize_t Dim>
|
528 |
+
struct type_caster<unchecked_reference<T, Dim>> {
|
529 |
+
static_assert(Dim == 0 && Dim > 0 /* always fail */,
|
530 |
+
"unchecked array proxy object is not castable");
|
531 |
+
};
|
532 |
+
template <typename T, ssize_t Dim>
|
533 |
+
struct type_caster<unchecked_mutable_reference<T, Dim>>
|
534 |
+
: type_caster<unchecked_reference<T, Dim>> {};
|
535 |
+
|
536 |
+
PYBIND11_NAMESPACE_END(detail)
|
537 |
+
|
538 |
+
class dtype : public object {
|
539 |
+
public:
|
540 |
+
PYBIND11_OBJECT_DEFAULT(dtype, object, detail::npy_api::get().PyArrayDescr_Check_);
|
541 |
+
|
542 |
+
explicit dtype(const buffer_info &info) {
|
543 |
+
dtype descr(_dtype_from_pep3118()(pybind11::str(info.format)));
|
544 |
+
// If info.itemsize == 0, use the value calculated from the format string
|
545 |
+
m_ptr = descr.strip_padding(info.itemsize != 0 ? info.itemsize : descr.itemsize())
|
546 |
+
.release()
|
547 |
+
.ptr();
|
548 |
+
}
|
549 |
+
|
550 |
+
explicit dtype(const pybind11::str &format) : dtype(from_args(format)) {}
|
551 |
+
|
552 |
+
explicit dtype(const std::string &format) : dtype(pybind11::str(format)) {}
|
553 |
+
|
554 |
+
explicit dtype(const char *format) : dtype(pybind11::str(format)) {}
|
555 |
+
|
556 |
+
dtype(list names, list formats, list offsets, ssize_t itemsize) {
|
557 |
+
dict args;
|
558 |
+
args["names"] = std::move(names);
|
559 |
+
args["formats"] = std::move(formats);
|
560 |
+
args["offsets"] = std::move(offsets);
|
561 |
+
args["itemsize"] = pybind11::int_(itemsize);
|
562 |
+
m_ptr = from_args(args).release().ptr();
|
563 |
+
}
|
564 |
+
|
565 |
+
explicit dtype(int typenum)
|
566 |
+
: object(detail::npy_api::get().PyArray_DescrFromType_(typenum), stolen_t{}) {
|
567 |
+
if (m_ptr == nullptr) {
|
568 |
+
throw error_already_set();
|
569 |
+
}
|
570 |
+
}
|
571 |
+
|
572 |
+
/// This is essentially the same as calling numpy.dtype(args) in Python.
|
573 |
+
static dtype from_args(const object &args) {
|
574 |
+
PyObject *ptr = nullptr;
|
575 |
+
if ((detail::npy_api::get().PyArray_DescrConverter_(args.ptr(), &ptr) == 0) || !ptr) {
|
576 |
+
throw error_already_set();
|
577 |
+
}
|
578 |
+
return reinterpret_steal<dtype>(ptr);
|
579 |
+
}
|
580 |
+
|
581 |
+
/// Return dtype associated with a C++ type.
|
582 |
+
template <typename T>
|
583 |
+
static dtype of() {
|
584 |
+
return detail::npy_format_descriptor<typename std::remove_cv<T>::type>::dtype();
|
585 |
+
}
|
586 |
+
|
587 |
+
/// Size of the data type in bytes.
|
588 |
+
ssize_t itemsize() const { return detail::array_descriptor_proxy(m_ptr)->elsize; }
|
589 |
+
|
590 |
+
/// Returns true for structured data types.
|
591 |
+
bool has_fields() const { return detail::array_descriptor_proxy(m_ptr)->names != nullptr; }
|
592 |
+
|
593 |
+
/// Single-character code for dtype's kind.
|
594 |
+
/// For example, floating point types are 'f' and integral types are 'i'.
|
595 |
+
char kind() const { return detail::array_descriptor_proxy(m_ptr)->kind; }
|
596 |
+
|
597 |
+
/// Single-character for dtype's type.
|
598 |
+
/// For example, ``float`` is 'f', ``double`` 'd', ``int`` 'i', and ``long`` 'l'.
|
599 |
+
char char_() const {
|
600 |
+
// Note: The signature, `dtype::char_` follows the naming of NumPy's
|
601 |
+
// public Python API (i.e., ``dtype.char``), rather than its internal
|
602 |
+
// C API (``PyArray_Descr::type``).
|
603 |
+
return detail::array_descriptor_proxy(m_ptr)->type;
|
604 |
+
}
|
605 |
+
|
606 |
+
/// type number of dtype.
|
607 |
+
int num() const {
|
608 |
+
// Note: The signature, `dtype::num` follows the naming of NumPy's public
|
609 |
+
// Python API (i.e., ``dtype.num``), rather than its internal
|
610 |
+
// C API (``PyArray_Descr::type_num``).
|
611 |
+
return detail::array_descriptor_proxy(m_ptr)->type_num;
|
612 |
+
}
|
613 |
+
|
614 |
+
/// Single character for byteorder
|
615 |
+
char byteorder() const { return detail::array_descriptor_proxy(m_ptr)->byteorder; }
|
616 |
+
|
617 |
+
/// Alignment of the data type
|
618 |
+
int alignment() const { return detail::array_descriptor_proxy(m_ptr)->alignment; }
|
619 |
+
|
620 |
+
/// Flags for the array descriptor
|
621 |
+
char flags() const { return detail::array_descriptor_proxy(m_ptr)->flags; }
|
622 |
+
|
623 |
+
private:
|
624 |
+
static object _dtype_from_pep3118() {
|
625 |
+
static PyObject *obj = module_::import("numpy.core._internal")
|
626 |
+
.attr("_dtype_from_pep3118")
|
627 |
+
.cast<object>()
|
628 |
+
.release()
|
629 |
+
.ptr();
|
630 |
+
return reinterpret_borrow<object>(obj);
|
631 |
+
}
|
632 |
+
|
633 |
+
dtype strip_padding(ssize_t itemsize) {
|
634 |
+
// Recursively strip all void fields with empty names that are generated for
|
635 |
+
// padding fields (as of NumPy v1.11).
|
636 |
+
if (!has_fields()) {
|
637 |
+
return *this;
|
638 |
+
}
|
639 |
+
|
640 |
+
struct field_descr {
|
641 |
+
pybind11::str name;
|
642 |
+
object format;
|
643 |
+
pybind11::int_ offset;
|
644 |
+
field_descr(pybind11::str &&name, object &&format, pybind11::int_ &&offset)
|
645 |
+
: name{std::move(name)}, format{std::move(format)}, offset{std::move(offset)} {};
|
646 |
+
};
|
647 |
+
auto field_dict = attr("fields").cast<dict>();
|
648 |
+
std::vector<field_descr> field_descriptors;
|
649 |
+
field_descriptors.reserve(field_dict.size());
|
650 |
+
|
651 |
+
for (auto field : field_dict.attr("items")()) {
|
652 |
+
auto spec = field.cast<tuple>();
|
653 |
+
auto name = spec[0].cast<pybind11::str>();
|
654 |
+
auto spec_fo = spec[1].cast<tuple>();
|
655 |
+
auto format = spec_fo[0].cast<dtype>();
|
656 |
+
auto offset = spec_fo[1].cast<pybind11::int_>();
|
657 |
+
if ((len(name) == 0u) && format.kind() == 'V') {
|
658 |
+
continue;
|
659 |
+
}
|
660 |
+
field_descriptors.emplace_back(
|
661 |
+
std::move(name), format.strip_padding(format.itemsize()), std::move(offset));
|
662 |
+
}
|
663 |
+
|
664 |
+
std::sort(field_descriptors.begin(),
|
665 |
+
field_descriptors.end(),
|
666 |
+
[](const field_descr &a, const field_descr &b) {
|
667 |
+
return a.offset.cast<int>() < b.offset.cast<int>();
|
668 |
+
});
|
669 |
+
|
670 |
+
list names, formats, offsets;
|
671 |
+
for (auto &descr : field_descriptors) {
|
672 |
+
names.append(std::move(descr.name));
|
673 |
+
formats.append(std::move(descr.format));
|
674 |
+
offsets.append(std::move(descr.offset));
|
675 |
+
}
|
676 |
+
return dtype(std::move(names), std::move(formats), std::move(offsets), itemsize);
|
677 |
+
}
|
678 |
+
};
|
679 |
+
|
680 |
+
class array : public buffer {
|
681 |
+
public:
|
682 |
+
PYBIND11_OBJECT_CVT(array, buffer, detail::npy_api::get().PyArray_Check_, raw_array)
|
683 |
+
|
684 |
+
enum {
|
685 |
+
c_style = detail::npy_api::NPY_ARRAY_C_CONTIGUOUS_,
|
686 |
+
f_style = detail::npy_api::NPY_ARRAY_F_CONTIGUOUS_,
|
687 |
+
forcecast = detail::npy_api::NPY_ARRAY_FORCECAST_
|
688 |
+
};
|
689 |
+
|
690 |
+
array() : array(0, static_cast<const double *>(nullptr)) {}
|
691 |
+
|
692 |
+
using ShapeContainer = detail::any_container<ssize_t>;
|
693 |
+
using StridesContainer = detail::any_container<ssize_t>;
|
694 |
+
|
695 |
+
// Constructs an array taking shape/strides from arbitrary container types
|
696 |
+
array(const pybind11::dtype &dt,
|
697 |
+
ShapeContainer shape,
|
698 |
+
StridesContainer strides,
|
699 |
+
const void *ptr = nullptr,
|
700 |
+
handle base = handle()) {
|
701 |
+
|
702 |
+
if (strides->empty()) {
|
703 |
+
*strides = detail::c_strides(*shape, dt.itemsize());
|
704 |
+
}
|
705 |
+
|
706 |
+
auto ndim = shape->size();
|
707 |
+
if (ndim != strides->size()) {
|
708 |
+
pybind11_fail("NumPy: shape ndim doesn't match strides ndim");
|
709 |
+
}
|
710 |
+
auto descr = dt;
|
711 |
+
|
712 |
+
int flags = 0;
|
713 |
+
if (base && ptr) {
|
714 |
+
if (isinstance<array>(base)) {
|
715 |
+
/* Copy flags from base (except ownership bit) */
|
716 |
+
flags = reinterpret_borrow<array>(base).flags()
|
717 |
+
& ~detail::npy_api::NPY_ARRAY_OWNDATA_;
|
718 |
+
} else {
|
719 |
+
/* Writable by default, easy to downgrade later on if needed */
|
720 |
+
flags = detail::npy_api::NPY_ARRAY_WRITEABLE_;
|
721 |
+
}
|
722 |
+
}
|
723 |
+
|
724 |
+
auto &api = detail::npy_api::get();
|
725 |
+
auto tmp = reinterpret_steal<object>(api.PyArray_NewFromDescr_(
|
726 |
+
api.PyArray_Type_,
|
727 |
+
descr.release().ptr(),
|
728 |
+
(int) ndim,
|
729 |
+
// Use reinterpret_cast for PyPy on Windows (remove if fixed, checked on 7.3.1)
|
730 |
+
reinterpret_cast<Py_intptr_t *>(shape->data()),
|
731 |
+
reinterpret_cast<Py_intptr_t *>(strides->data()),
|
732 |
+
const_cast<void *>(ptr),
|
733 |
+
flags,
|
734 |
+
nullptr));
|
735 |
+
if (!tmp) {
|
736 |
+
throw error_already_set();
|
737 |
+
}
|
738 |
+
if (ptr) {
|
739 |
+
if (base) {
|
740 |
+
api.PyArray_SetBaseObject_(tmp.ptr(), base.inc_ref().ptr());
|
741 |
+
} else {
|
742 |
+
tmp = reinterpret_steal<object>(
|
743 |
+
api.PyArray_NewCopy_(tmp.ptr(), -1 /* any order */));
|
744 |
+
}
|
745 |
+
}
|
746 |
+
m_ptr = tmp.release().ptr();
|
747 |
+
}
|
748 |
+
|
749 |
+
array(const pybind11::dtype &dt,
|
750 |
+
ShapeContainer shape,
|
751 |
+
const void *ptr = nullptr,
|
752 |
+
handle base = handle())
|
753 |
+
: array(dt, std::move(shape), {}, ptr, base) {}
|
754 |
+
|
755 |
+
template <typename T,
|
756 |
+
typename
|
757 |
+
= detail::enable_if_t<std::is_integral<T>::value && !std::is_same<bool, T>::value>>
|
758 |
+
array(const pybind11::dtype &dt, T count, const void *ptr = nullptr, handle base = handle())
|
759 |
+
: array(dt, {{count}}, ptr, base) {}
|
760 |
+
|
761 |
+
template <typename T>
|
762 |
+
array(ShapeContainer shape, StridesContainer strides, const T *ptr, handle base = handle())
|
763 |
+
: array(pybind11::dtype::of<T>(), std::move(shape), std::move(strides), ptr, base) {}
|
764 |
+
|
765 |
+
template <typename T>
|
766 |
+
array(ShapeContainer shape, const T *ptr, handle base = handle())
|
767 |
+
: array(std::move(shape), {}, ptr, base) {}
|
768 |
+
|
769 |
+
template <typename T>
|
770 |
+
explicit array(ssize_t count, const T *ptr, handle base = handle())
|
771 |
+
: array({count}, {}, ptr, base) {}
|
772 |
+
|
773 |
+
explicit array(const buffer_info &info, handle base = handle())
|
774 |
+
: array(pybind11::dtype(info), info.shape, info.strides, info.ptr, base) {}
|
775 |
+
|
776 |
+
/// Array descriptor (dtype)
|
777 |
+
pybind11::dtype dtype() const {
|
778 |
+
return reinterpret_borrow<pybind11::dtype>(detail::array_proxy(m_ptr)->descr);
|
779 |
+
}
|
780 |
+
|
781 |
+
/// Total number of elements
|
782 |
+
ssize_t size() const {
|
783 |
+
return std::accumulate(shape(), shape() + ndim(), (ssize_t) 1, std::multiplies<ssize_t>());
|
784 |
+
}
|
785 |
+
|
786 |
+
/// Byte size of a single element
|
787 |
+
ssize_t itemsize() const {
|
788 |
+
return detail::array_descriptor_proxy(detail::array_proxy(m_ptr)->descr)->elsize;
|
789 |
+
}
|
790 |
+
|
791 |
+
/// Total number of bytes
|
792 |
+
ssize_t nbytes() const { return size() * itemsize(); }
|
793 |
+
|
794 |
+
/// Number of dimensions
|
795 |
+
ssize_t ndim() const { return detail::array_proxy(m_ptr)->nd; }
|
796 |
+
|
797 |
+
/// Base object
|
798 |
+
object base() const { return reinterpret_borrow<object>(detail::array_proxy(m_ptr)->base); }
|
799 |
+
|
800 |
+
/// Dimensions of the array
|
801 |
+
const ssize_t *shape() const { return detail::array_proxy(m_ptr)->dimensions; }
|
802 |
+
|
803 |
+
/// Dimension along a given axis
|
804 |
+
ssize_t shape(ssize_t dim) const {
|
805 |
+
if (dim >= ndim()) {
|
806 |
+
fail_dim_check(dim, "invalid axis");
|
807 |
+
}
|
808 |
+
return shape()[dim];
|
809 |
+
}
|
810 |
+
|
811 |
+
/// Strides of the array
|
812 |
+
const ssize_t *strides() const { return detail::array_proxy(m_ptr)->strides; }
|
813 |
+
|
814 |
+
/// Stride along a given axis
|
815 |
+
ssize_t strides(ssize_t dim) const {
|
816 |
+
if (dim >= ndim()) {
|
817 |
+
fail_dim_check(dim, "invalid axis");
|
818 |
+
}
|
819 |
+
return strides()[dim];
|
820 |
+
}
|
821 |
+
|
822 |
+
/// Return the NumPy array flags
|
823 |
+
int flags() const { return detail::array_proxy(m_ptr)->flags; }
|
824 |
+
|
825 |
+
/// If set, the array is writeable (otherwise the buffer is read-only)
|
826 |
+
bool writeable() const {
|
827 |
+
return detail::check_flags(m_ptr, detail::npy_api::NPY_ARRAY_WRITEABLE_);
|
828 |
+
}
|
829 |
+
|
830 |
+
/// If set, the array owns the data (will be freed when the array is deleted)
|
831 |
+
bool owndata() const {
|
832 |
+
return detail::check_flags(m_ptr, detail::npy_api::NPY_ARRAY_OWNDATA_);
|
833 |
+
}
|
834 |
+
|
835 |
+
/// Pointer to the contained data. If index is not provided, points to the
|
836 |
+
/// beginning of the buffer. May throw if the index would lead to out of bounds access.
|
837 |
+
template <typename... Ix>
|
838 |
+
const void *data(Ix... index) const {
|
839 |
+
return static_cast<const void *>(detail::array_proxy(m_ptr)->data + offset_at(index...));
|
840 |
+
}
|
841 |
+
|
842 |
+
/// Mutable pointer to the contained data. If index is not provided, points to the
|
843 |
+
/// beginning of the buffer. May throw if the index would lead to out of bounds access.
|
844 |
+
/// May throw if the array is not writeable.
|
845 |
+
template <typename... Ix>
|
846 |
+
void *mutable_data(Ix... index) {
|
847 |
+
check_writeable();
|
848 |
+
return static_cast<void *>(detail::array_proxy(m_ptr)->data + offset_at(index...));
|
849 |
+
}
|
850 |
+
|
851 |
+
/// Byte offset from beginning of the array to a given index (full or partial).
|
852 |
+
/// May throw if the index would lead to out of bounds access.
|
853 |
+
template <typename... Ix>
|
854 |
+
ssize_t offset_at(Ix... index) const {
|
855 |
+
if ((ssize_t) sizeof...(index) > ndim()) {
|
856 |
+
fail_dim_check(sizeof...(index), "too many indices for an array");
|
857 |
+
}
|
858 |
+
return byte_offset(ssize_t(index)...);
|
859 |
+
}
|
860 |
+
|
861 |
+
ssize_t offset_at() const { return 0; }
|
862 |
+
|
863 |
+
/// Item count from beginning of the array to a given index (full or partial).
|
864 |
+
/// May throw if the index would lead to out of bounds access.
|
865 |
+
template <typename... Ix>
|
866 |
+
ssize_t index_at(Ix... index) const {
|
867 |
+
return offset_at(index...) / itemsize();
|
868 |
+
}
|
869 |
+
|
870 |
+
/**
|
871 |
+
* Returns a proxy object that provides access to the array's data without bounds or
|
872 |
+
* dimensionality checking. Will throw if the array is missing the `writeable` flag. Use with
|
873 |
+
* care: the array must not be destroyed or reshaped for the duration of the returned object,
|
874 |
+
* and the caller must take care not to access invalid dimensions or dimension indices.
|
875 |
+
*/
|
876 |
+
template <typename T, ssize_t Dims = -1>
|
877 |
+
detail::unchecked_mutable_reference<T, Dims> mutable_unchecked() & {
|
878 |
+
if (PYBIND11_SILENCE_MSVC_C4127(Dims >= 0) && ndim() != Dims) {
|
879 |
+
throw std::domain_error("array has incorrect number of dimensions: "
|
880 |
+
+ std::to_string(ndim()) + "; expected "
|
881 |
+
+ std::to_string(Dims));
|
882 |
+
}
|
883 |
+
return detail::unchecked_mutable_reference<T, Dims>(
|
884 |
+
mutable_data(), shape(), strides(), ndim());
|
885 |
+
}
|
886 |
+
|
887 |
+
/**
|
888 |
+
* Returns a proxy object that provides const access to the array's data without bounds or
|
889 |
+
* dimensionality checking. Unlike `mutable_unchecked()`, this does not require that the
|
890 |
+
* underlying array have the `writable` flag. Use with care: the array must not be destroyed
|
891 |
+
* or reshaped for the duration of the returned object, and the caller must take care not to
|
892 |
+
* access invalid dimensions or dimension indices.
|
893 |
+
*/
|
894 |
+
template <typename T, ssize_t Dims = -1>
|
895 |
+
detail::unchecked_reference<T, Dims> unchecked() const & {
|
896 |
+
if (PYBIND11_SILENCE_MSVC_C4127(Dims >= 0) && ndim() != Dims) {
|
897 |
+
throw std::domain_error("array has incorrect number of dimensions: "
|
898 |
+
+ std::to_string(ndim()) + "; expected "
|
899 |
+
+ std::to_string(Dims));
|
900 |
+
}
|
901 |
+
return detail::unchecked_reference<T, Dims>(data(), shape(), strides(), ndim());
|
902 |
+
}
|
903 |
+
|
904 |
+
/// Return a new view with all of the dimensions of length 1 removed
|
905 |
+
array squeeze() {
|
906 |
+
auto &api = detail::npy_api::get();
|
907 |
+
return reinterpret_steal<array>(api.PyArray_Squeeze_(m_ptr));
|
908 |
+
}
|
909 |
+
|
910 |
+
/// Resize array to given shape
|
911 |
+
/// If refcheck is true and more that one reference exist to this array
|
912 |
+
/// then resize will succeed only if it makes a reshape, i.e. original size doesn't change
|
913 |
+
void resize(ShapeContainer new_shape, bool refcheck = true) {
|
914 |
+
detail::npy_api::PyArray_Dims d
|
915 |
+
= {// Use reinterpret_cast for PyPy on Windows (remove if fixed, checked on 7.3.1)
|
916 |
+
reinterpret_cast<Py_intptr_t *>(new_shape->data()),
|
917 |
+
int(new_shape->size())};
|
918 |
+
// try to resize, set ordering param to -1 cause it's not used anyway
|
919 |
+
auto new_array = reinterpret_steal<object>(
|
920 |
+
detail::npy_api::get().PyArray_Resize_(m_ptr, &d, int(refcheck), -1));
|
921 |
+
if (!new_array) {
|
922 |
+
throw error_already_set();
|
923 |
+
}
|
924 |
+
if (isinstance<array>(new_array)) {
|
925 |
+
*this = std::move(new_array);
|
926 |
+
}
|
927 |
+
}
|
928 |
+
|
929 |
+
/// Optional `order` parameter omitted, to be added as needed.
|
930 |
+
array reshape(ShapeContainer new_shape) {
|
931 |
+
detail::npy_api::PyArray_Dims d
|
932 |
+
= {reinterpret_cast<Py_intptr_t *>(new_shape->data()), int(new_shape->size())};
|
933 |
+
auto new_array
|
934 |
+
= reinterpret_steal<array>(detail::npy_api::get().PyArray_Newshape_(m_ptr, &d, 0));
|
935 |
+
if (!new_array) {
|
936 |
+
throw error_already_set();
|
937 |
+
}
|
938 |
+
return new_array;
|
939 |
+
}
|
940 |
+
|
941 |
+
/// Create a view of an array in a different data type.
|
942 |
+
/// This function may fundamentally reinterpret the data in the array.
|
943 |
+
/// It is the responsibility of the caller to ensure that this is safe.
|
944 |
+
/// Only supports the `dtype` argument, the `type` argument is omitted,
|
945 |
+
/// to be added as needed.
|
946 |
+
array view(const std::string &dtype) {
|
947 |
+
auto &api = detail::npy_api::get();
|
948 |
+
auto new_view = reinterpret_steal<array>(api.PyArray_View_(
|
949 |
+
m_ptr, dtype::from_args(pybind11::str(dtype)).release().ptr(), nullptr));
|
950 |
+
if (!new_view) {
|
951 |
+
throw error_already_set();
|
952 |
+
}
|
953 |
+
return new_view;
|
954 |
+
}
|
955 |
+
|
956 |
+
/// Ensure that the argument is a NumPy array
|
957 |
+
/// In case of an error, nullptr is returned and the Python error is cleared.
|
958 |
+
static array ensure(handle h, int ExtraFlags = 0) {
|
959 |
+
auto result = reinterpret_steal<array>(raw_array(h.ptr(), ExtraFlags));
|
960 |
+
if (!result) {
|
961 |
+
PyErr_Clear();
|
962 |
+
}
|
963 |
+
return result;
|
964 |
+
}
|
965 |
+
|
966 |
+
protected:
|
967 |
+
template <typename, typename>
|
968 |
+
friend struct detail::npy_format_descriptor;
|
969 |
+
|
970 |
+
void fail_dim_check(ssize_t dim, const std::string &msg) const {
|
971 |
+
throw index_error(msg + ": " + std::to_string(dim) + " (ndim = " + std::to_string(ndim())
|
972 |
+
+ ')');
|
973 |
+
}
|
974 |
+
|
975 |
+
template <typename... Ix>
|
976 |
+
ssize_t byte_offset(Ix... index) const {
|
977 |
+
check_dimensions(index...);
|
978 |
+
return detail::byte_offset_unsafe(strides(), ssize_t(index)...);
|
979 |
+
}
|
980 |
+
|
981 |
+
void check_writeable() const {
|
982 |
+
if (!writeable()) {
|
983 |
+
throw std::domain_error("array is not writeable");
|
984 |
+
}
|
985 |
+
}
|
986 |
+
|
987 |
+
template <typename... Ix>
|
988 |
+
void check_dimensions(Ix... index) const {
|
989 |
+
check_dimensions_impl(ssize_t(0), shape(), ssize_t(index)...);
|
990 |
+
}
|
991 |
+
|
992 |
+
void check_dimensions_impl(ssize_t, const ssize_t *) const {}
|
993 |
+
|
994 |
+
template <typename... Ix>
|
995 |
+
void check_dimensions_impl(ssize_t axis, const ssize_t *shape, ssize_t i, Ix... index) const {
|
996 |
+
if (i >= *shape) {
|
997 |
+
throw index_error(std::string("index ") + std::to_string(i)
|
998 |
+
+ " is out of bounds for axis " + std::to_string(axis)
|
999 |
+
+ " with size " + std::to_string(*shape));
|
1000 |
+
}
|
1001 |
+
check_dimensions_impl(axis + 1, shape + 1, index...);
|
1002 |
+
}
|
1003 |
+
|
1004 |
+
/// Create array from any object -- always returns a new reference
|
1005 |
+
static PyObject *raw_array(PyObject *ptr, int ExtraFlags = 0) {
|
1006 |
+
if (ptr == nullptr) {
|
1007 |
+
PyErr_SetString(PyExc_ValueError, "cannot create a pybind11::array from a nullptr");
|
1008 |
+
return nullptr;
|
1009 |
+
}
|
1010 |
+
return detail::npy_api::get().PyArray_FromAny_(
|
1011 |
+
ptr, nullptr, 0, 0, detail::npy_api::NPY_ARRAY_ENSUREARRAY_ | ExtraFlags, nullptr);
|
1012 |
+
}
|
1013 |
+
};
|
1014 |
+
|
1015 |
+
template <typename T, int ExtraFlags = array::forcecast>
|
1016 |
+
class array_t : public array {
|
1017 |
+
private:
|
1018 |
+
struct private_ctor {};
|
1019 |
+
// Delegating constructor needed when both moving and accessing in the same constructor
|
1020 |
+
array_t(private_ctor,
|
1021 |
+
ShapeContainer &&shape,
|
1022 |
+
StridesContainer &&strides,
|
1023 |
+
const T *ptr,
|
1024 |
+
handle base)
|
1025 |
+
: array(std::move(shape), std::move(strides), ptr, base) {}
|
1026 |
+
|
1027 |
+
public:
|
1028 |
+
static_assert(!detail::array_info<T>::is_array, "Array types cannot be used with array_t");
|
1029 |
+
|
1030 |
+
using value_type = T;
|
1031 |
+
|
1032 |
+
array_t() : array(0, static_cast<const T *>(nullptr)) {}
|
1033 |
+
array_t(handle h, borrowed_t) : array(h, borrowed_t{}) {}
|
1034 |
+
array_t(handle h, stolen_t) : array(h, stolen_t{}) {}
|
1035 |
+
|
1036 |
+
PYBIND11_DEPRECATED("Use array_t<T>::ensure() instead")
|
1037 |
+
array_t(handle h, bool is_borrowed) : array(raw_array_t(h.ptr()), stolen_t{}) {
|
1038 |
+
if (!m_ptr) {
|
1039 |
+
PyErr_Clear();
|
1040 |
+
}
|
1041 |
+
if (!is_borrowed) {
|
1042 |
+
Py_XDECREF(h.ptr());
|
1043 |
+
}
|
1044 |
+
}
|
1045 |
+
|
1046 |
+
// NOLINTNEXTLINE(google-explicit-constructor)
|
1047 |
+
array_t(const object &o) : array(raw_array_t(o.ptr()), stolen_t{}) {
|
1048 |
+
if (!m_ptr) {
|
1049 |
+
throw error_already_set();
|
1050 |
+
}
|
1051 |
+
}
|
1052 |
+
|
1053 |
+
explicit array_t(const buffer_info &info, handle base = handle()) : array(info, base) {}
|
1054 |
+
|
1055 |
+
array_t(ShapeContainer shape,
|
1056 |
+
StridesContainer strides,
|
1057 |
+
const T *ptr = nullptr,
|
1058 |
+
handle base = handle())
|
1059 |
+
: array(std::move(shape), std::move(strides), ptr, base) {}
|
1060 |
+
|
1061 |
+
explicit array_t(ShapeContainer shape, const T *ptr = nullptr, handle base = handle())
|
1062 |
+
: array_t(private_ctor{},
|
1063 |
+
std::move(shape),
|
1064 |
+
(ExtraFlags & f_style) != 0 ? detail::f_strides(*shape, itemsize())
|
1065 |
+
: detail::c_strides(*shape, itemsize()),
|
1066 |
+
ptr,
|
1067 |
+
base) {}
|
1068 |
+
|
1069 |
+
explicit array_t(ssize_t count, const T *ptr = nullptr, handle base = handle())
|
1070 |
+
: array({count}, {}, ptr, base) {}
|
1071 |
+
|
1072 |
+
constexpr ssize_t itemsize() const { return sizeof(T); }
|
1073 |
+
|
1074 |
+
template <typename... Ix>
|
1075 |
+
ssize_t index_at(Ix... index) const {
|
1076 |
+
return offset_at(index...) / itemsize();
|
1077 |
+
}
|
1078 |
+
|
1079 |
+
template <typename... Ix>
|
1080 |
+
const T *data(Ix... index) const {
|
1081 |
+
return static_cast<const T *>(array::data(index...));
|
1082 |
+
}
|
1083 |
+
|
1084 |
+
template <typename... Ix>
|
1085 |
+
T *mutable_data(Ix... index) {
|
1086 |
+
return static_cast<T *>(array::mutable_data(index...));
|
1087 |
+
}
|
1088 |
+
|
1089 |
+
// Reference to element at a given index
|
1090 |
+
template <typename... Ix>
|
1091 |
+
const T &at(Ix... index) const {
|
1092 |
+
if ((ssize_t) sizeof...(index) != ndim()) {
|
1093 |
+
fail_dim_check(sizeof...(index), "index dimension mismatch");
|
1094 |
+
}
|
1095 |
+
return *(static_cast<const T *>(array::data())
|
1096 |
+
+ byte_offset(ssize_t(index)...) / itemsize());
|
1097 |
+
}
|
1098 |
+
|
1099 |
+
// Mutable reference to element at a given index
|
1100 |
+
template <typename... Ix>
|
1101 |
+
T &mutable_at(Ix... index) {
|
1102 |
+
if ((ssize_t) sizeof...(index) != ndim()) {
|
1103 |
+
fail_dim_check(sizeof...(index), "index dimension mismatch");
|
1104 |
+
}
|
1105 |
+
return *(static_cast<T *>(array::mutable_data())
|
1106 |
+
+ byte_offset(ssize_t(index)...) / itemsize());
|
1107 |
+
}
|
1108 |
+
|
1109 |
+
/**
|
1110 |
+
* Returns a proxy object that provides access to the array's data without bounds or
|
1111 |
+
* dimensionality checking. Will throw if the array is missing the `writeable` flag. Use with
|
1112 |
+
* care: the array must not be destroyed or reshaped for the duration of the returned object,
|
1113 |
+
* and the caller must take care not to access invalid dimensions or dimension indices.
|
1114 |
+
*/
|
1115 |
+
template <ssize_t Dims = -1>
|
1116 |
+
detail::unchecked_mutable_reference<T, Dims> mutable_unchecked() & {
|
1117 |
+
return array::mutable_unchecked<T, Dims>();
|
1118 |
+
}
|
1119 |
+
|
1120 |
+
/**
|
1121 |
+
* Returns a proxy object that provides const access to the array's data without bounds or
|
1122 |
+
* dimensionality checking. Unlike `unchecked()`, this does not require that the underlying
|
1123 |
+
* array have the `writable` flag. Use with care: the array must not be destroyed or reshaped
|
1124 |
+
* for the duration of the returned object, and the caller must take care not to access invalid
|
1125 |
+
* dimensions or dimension indices.
|
1126 |
+
*/
|
1127 |
+
template <ssize_t Dims = -1>
|
1128 |
+
detail::unchecked_reference<T, Dims> unchecked() const & {
|
1129 |
+
return array::unchecked<T, Dims>();
|
1130 |
+
}
|
1131 |
+
|
1132 |
+
/// Ensure that the argument is a NumPy array of the correct dtype (and if not, try to convert
|
1133 |
+
/// it). In case of an error, nullptr is returned and the Python error is cleared.
|
1134 |
+
static array_t ensure(handle h) {
|
1135 |
+
auto result = reinterpret_steal<array_t>(raw_array_t(h.ptr()));
|
1136 |
+
if (!result) {
|
1137 |
+
PyErr_Clear();
|
1138 |
+
}
|
1139 |
+
return result;
|
1140 |
+
}
|
1141 |
+
|
1142 |
+
static bool check_(handle h) {
|
1143 |
+
const auto &api = detail::npy_api::get();
|
1144 |
+
return api.PyArray_Check_(h.ptr())
|
1145 |
+
&& api.PyArray_EquivTypes_(detail::array_proxy(h.ptr())->descr,
|
1146 |
+
dtype::of<T>().ptr())
|
1147 |
+
&& detail::check_flags(h.ptr(), ExtraFlags & (array::c_style | array::f_style));
|
1148 |
+
}
|
1149 |
+
|
1150 |
+
protected:
|
1151 |
+
/// Create array from any object -- always returns a new reference
|
1152 |
+
static PyObject *raw_array_t(PyObject *ptr) {
|
1153 |
+
if (ptr == nullptr) {
|
1154 |
+
PyErr_SetString(PyExc_ValueError, "cannot create a pybind11::array_t from a nullptr");
|
1155 |
+
return nullptr;
|
1156 |
+
}
|
1157 |
+
return detail::npy_api::get().PyArray_FromAny_(ptr,
|
1158 |
+
dtype::of<T>().release().ptr(),
|
1159 |
+
0,
|
1160 |
+
0,
|
1161 |
+
detail::npy_api::NPY_ARRAY_ENSUREARRAY_
|
1162 |
+
| ExtraFlags,
|
1163 |
+
nullptr);
|
1164 |
+
}
|
1165 |
+
};
|
1166 |
+
|
1167 |
+
template <typename T>
|
1168 |
+
struct format_descriptor<T, detail::enable_if_t<detail::is_pod_struct<T>::value>> {
|
1169 |
+
static std::string format() {
|
1170 |
+
return detail::npy_format_descriptor<typename std::remove_cv<T>::type>::format();
|
1171 |
+
}
|
1172 |
+
};
|
1173 |
+
|
1174 |
+
template <size_t N>
|
1175 |
+
struct format_descriptor<char[N]> {
|
1176 |
+
static std::string format() { return std::to_string(N) + 's'; }
|
1177 |
+
};
|
1178 |
+
template <size_t N>
|
1179 |
+
struct format_descriptor<std::array<char, N>> {
|
1180 |
+
static std::string format() { return std::to_string(N) + 's'; }
|
1181 |
+
};
|
1182 |
+
|
1183 |
+
template <typename T>
|
1184 |
+
struct format_descriptor<T, detail::enable_if_t<std::is_enum<T>::value>> {
|
1185 |
+
static std::string format() {
|
1186 |
+
return format_descriptor<
|
1187 |
+
typename std::remove_cv<typename std::underlying_type<T>::type>::type>::format();
|
1188 |
+
}
|
1189 |
+
};
|
1190 |
+
|
1191 |
+
template <typename T>
|
1192 |
+
struct format_descriptor<T, detail::enable_if_t<detail::array_info<T>::is_array>> {
|
1193 |
+
static std::string format() {
|
1194 |
+
using namespace detail;
|
1195 |
+
static constexpr auto extents = const_name("(") + array_info<T>::extents + const_name(")");
|
1196 |
+
return extents.text + format_descriptor<remove_all_extents_t<T>>::format();
|
1197 |
+
}
|
1198 |
+
};
|
1199 |
+
|
1200 |
+
PYBIND11_NAMESPACE_BEGIN(detail)
|
1201 |
+
template <typename T, int ExtraFlags>
|
1202 |
+
struct pyobject_caster<array_t<T, ExtraFlags>> {
|
1203 |
+
using type = array_t<T, ExtraFlags>;
|
1204 |
+
|
1205 |
+
bool load(handle src, bool convert) {
|
1206 |
+
if (!convert && !type::check_(src)) {
|
1207 |
+
return false;
|
1208 |
+
}
|
1209 |
+
value = type::ensure(src);
|
1210 |
+
return static_cast<bool>(value);
|
1211 |
+
}
|
1212 |
+
|
1213 |
+
static handle cast(const handle &src, return_value_policy /* policy */, handle /* parent */) {
|
1214 |
+
return src.inc_ref();
|
1215 |
+
}
|
1216 |
+
PYBIND11_TYPE_CASTER(type, handle_type_name<type>::name);
|
1217 |
+
};
|
1218 |
+
|
1219 |
+
template <typename T>
|
1220 |
+
struct compare_buffer_info<T, detail::enable_if_t<detail::is_pod_struct<T>::value>> {
|
1221 |
+
static bool compare(const buffer_info &b) {
|
1222 |
+
return npy_api::get().PyArray_EquivTypes_(dtype::of<T>().ptr(), dtype(b).ptr());
|
1223 |
+
}
|
1224 |
+
};
|
1225 |
+
|
1226 |
+
template <typename T, typename = void>
|
1227 |
+
struct npy_format_descriptor_name;
|
1228 |
+
|
1229 |
+
template <typename T>
|
1230 |
+
struct npy_format_descriptor_name<T, enable_if_t<std::is_integral<T>::value>> {
|
1231 |
+
static constexpr auto name = const_name<std::is_same<T, bool>::value>(
|
1232 |
+
const_name("bool"),
|
1233 |
+
const_name<std::is_signed<T>::value>("numpy.int", "numpy.uint")
|
1234 |
+
+ const_name<sizeof(T) * 8>());
|
1235 |
+
};
|
1236 |
+
|
1237 |
+
template <typename T>
|
1238 |
+
struct npy_format_descriptor_name<T, enable_if_t<std::is_floating_point<T>::value>> {
|
1239 |
+
static constexpr auto name = const_name < std::is_same<T, float>::value
|
1240 |
+
|| std::is_same<T, const float>::value
|
1241 |
+
|| std::is_same<T, double>::value
|
1242 |
+
|| std::is_same<T, const double>::value
|
1243 |
+
> (const_name("numpy.float") + const_name<sizeof(T) * 8>(),
|
1244 |
+
const_name("numpy.longdouble"));
|
1245 |
+
};
|
1246 |
+
|
1247 |
+
template <typename T>
|
1248 |
+
struct npy_format_descriptor_name<T, enable_if_t<is_complex<T>::value>> {
|
1249 |
+
static constexpr auto name = const_name < std::is_same<typename T::value_type, float>::value
|
1250 |
+
|| std::is_same<typename T::value_type, const float>::value
|
1251 |
+
|| std::is_same<typename T::value_type, double>::value
|
1252 |
+
|| std::is_same<typename T::value_type, const double>::value
|
1253 |
+
> (const_name("numpy.complex")
|
1254 |
+
+ const_name<sizeof(typename T::value_type) * 16>(),
|
1255 |
+
const_name("numpy.longcomplex"));
|
1256 |
+
};
|
1257 |
+
|
1258 |
+
template <typename T>
|
1259 |
+
struct npy_format_descriptor<
|
1260 |
+
T,
|
1261 |
+
enable_if_t<satisfies_any_of<T, std::is_arithmetic, is_complex>::value>>
|
1262 |
+
: npy_format_descriptor_name<T> {
|
1263 |
+
private:
|
1264 |
+
// NB: the order here must match the one in common.h
|
1265 |
+
constexpr static const int values[15] = {npy_api::NPY_BOOL_,
|
1266 |
+
npy_api::NPY_BYTE_,
|
1267 |
+
npy_api::NPY_UBYTE_,
|
1268 |
+
npy_api::NPY_INT16_,
|
1269 |
+
npy_api::NPY_UINT16_,
|
1270 |
+
npy_api::NPY_INT32_,
|
1271 |
+
npy_api::NPY_UINT32_,
|
1272 |
+
npy_api::NPY_INT64_,
|
1273 |
+
npy_api::NPY_UINT64_,
|
1274 |
+
npy_api::NPY_FLOAT_,
|
1275 |
+
npy_api::NPY_DOUBLE_,
|
1276 |
+
npy_api::NPY_LONGDOUBLE_,
|
1277 |
+
npy_api::NPY_CFLOAT_,
|
1278 |
+
npy_api::NPY_CDOUBLE_,
|
1279 |
+
npy_api::NPY_CLONGDOUBLE_};
|
1280 |
+
|
1281 |
+
public:
|
1282 |
+
static constexpr int value = values[detail::is_fmt_numeric<T>::index];
|
1283 |
+
|
1284 |
+
static pybind11::dtype dtype() {
|
1285 |
+
if (auto *ptr = npy_api::get().PyArray_DescrFromType_(value)) {
|
1286 |
+
return reinterpret_steal<pybind11::dtype>(ptr);
|
1287 |
+
}
|
1288 |
+
pybind11_fail("Unsupported buffer format!");
|
1289 |
+
}
|
1290 |
+
};
|
1291 |
+
|
1292 |
+
#define PYBIND11_DECL_CHAR_FMT \
|
1293 |
+
static constexpr auto name = const_name("S") + const_name<N>(); \
|
1294 |
+
static pybind11::dtype dtype() { \
|
1295 |
+
return pybind11::dtype(std::string("S") + std::to_string(N)); \
|
1296 |
+
}
|
1297 |
+
template <size_t N>
|
1298 |
+
struct npy_format_descriptor<char[N]> {
|
1299 |
+
PYBIND11_DECL_CHAR_FMT
|
1300 |
+
};
|
1301 |
+
template <size_t N>
|
1302 |
+
struct npy_format_descriptor<std::array<char, N>> {
|
1303 |
+
PYBIND11_DECL_CHAR_FMT
|
1304 |
+
};
|
1305 |
+
#undef PYBIND11_DECL_CHAR_FMT
|
1306 |
+
|
1307 |
+
template <typename T>
|
1308 |
+
struct npy_format_descriptor<T, enable_if_t<array_info<T>::is_array>> {
|
1309 |
+
private:
|
1310 |
+
using base_descr = npy_format_descriptor<typename array_info<T>::type>;
|
1311 |
+
|
1312 |
+
public:
|
1313 |
+
static_assert(!array_info<T>::is_empty, "Zero-sized arrays are not supported");
|
1314 |
+
|
1315 |
+
static constexpr auto name
|
1316 |
+
= const_name("(") + array_info<T>::extents + const_name(")") + base_descr::name;
|
1317 |
+
static pybind11::dtype dtype() {
|
1318 |
+
list shape;
|
1319 |
+
array_info<T>::append_extents(shape);
|
1320 |
+
return pybind11::dtype::from_args(
|
1321 |
+
pybind11::make_tuple(base_descr::dtype(), std::move(shape)));
|
1322 |
+
}
|
1323 |
+
};
|
1324 |
+
|
1325 |
+
template <typename T>
|
1326 |
+
struct npy_format_descriptor<T, enable_if_t<std::is_enum<T>::value>> {
|
1327 |
+
private:
|
1328 |
+
using base_descr = npy_format_descriptor<typename std::underlying_type<T>::type>;
|
1329 |
+
|
1330 |
+
public:
|
1331 |
+
static constexpr auto name = base_descr::name;
|
1332 |
+
static pybind11::dtype dtype() { return base_descr::dtype(); }
|
1333 |
+
};
|
1334 |
+
|
1335 |
+
struct field_descriptor {
|
1336 |
+
const char *name;
|
1337 |
+
ssize_t offset;
|
1338 |
+
ssize_t size;
|
1339 |
+
std::string format;
|
1340 |
+
dtype descr;
|
1341 |
+
};
|
1342 |
+
|
1343 |
+
PYBIND11_NOINLINE void register_structured_dtype(any_container<field_descriptor> fields,
|
1344 |
+
const std::type_info &tinfo,
|
1345 |
+
ssize_t itemsize,
|
1346 |
+
bool (*direct_converter)(PyObject *, void *&)) {
|
1347 |
+
|
1348 |
+
auto &numpy_internals = get_numpy_internals();
|
1349 |
+
if (numpy_internals.get_type_info(tinfo, false)) {
|
1350 |
+
pybind11_fail("NumPy: dtype is already registered");
|
1351 |
+
}
|
1352 |
+
|
1353 |
+
// Use ordered fields because order matters as of NumPy 1.14:
|
1354 |
+
// https://docs.scipy.org/doc/numpy/release.html#multiple-field-indexing-assignment-of-structured-arrays
|
1355 |
+
std::vector<field_descriptor> ordered_fields(std::move(fields));
|
1356 |
+
std::sort(
|
1357 |
+
ordered_fields.begin(),
|
1358 |
+
ordered_fields.end(),
|
1359 |
+
[](const field_descriptor &a, const field_descriptor &b) { return a.offset < b.offset; });
|
1360 |
+
|
1361 |
+
list names, formats, offsets;
|
1362 |
+
for (auto &field : ordered_fields) {
|
1363 |
+
if (!field.descr) {
|
1364 |
+
pybind11_fail(std::string("NumPy: unsupported field dtype: `") + field.name + "` @ "
|
1365 |
+
+ tinfo.name());
|
1366 |
+
}
|
1367 |
+
names.append(pybind11::str(field.name));
|
1368 |
+
formats.append(field.descr);
|
1369 |
+
offsets.append(pybind11::int_(field.offset));
|
1370 |
+
}
|
1371 |
+
auto *dtype_ptr
|
1372 |
+
= pybind11::dtype(std::move(names), std::move(formats), std::move(offsets), itemsize)
|
1373 |
+
.release()
|
1374 |
+
.ptr();
|
1375 |
+
|
1376 |
+
// There is an existing bug in NumPy (as of v1.11): trailing bytes are
|
1377 |
+
// not encoded explicitly into the format string. This will supposedly
|
1378 |
+
// get fixed in v1.12; for further details, see these:
|
1379 |
+
// - https://github.com/numpy/numpy/issues/7797
|
1380 |
+
// - https://github.com/numpy/numpy/pull/7798
|
1381 |
+
// Because of this, we won't use numpy's logic to generate buffer format
|
1382 |
+
// strings and will just do it ourselves.
|
1383 |
+
ssize_t offset = 0;
|
1384 |
+
std::ostringstream oss;
|
1385 |
+
// mark the structure as unaligned with '^', because numpy and C++ don't
|
1386 |
+
// always agree about alignment (particularly for complex), and we're
|
1387 |
+
// explicitly listing all our padding. This depends on none of the fields
|
1388 |
+
// overriding the endianness. Putting the ^ in front of individual fields
|
1389 |
+
// isn't guaranteed to work due to https://github.com/numpy/numpy/issues/9049
|
1390 |
+
oss << "^T{";
|
1391 |
+
for (auto &field : ordered_fields) {
|
1392 |
+
if (field.offset > offset) {
|
1393 |
+
oss << (field.offset - offset) << 'x';
|
1394 |
+
}
|
1395 |
+
oss << field.format << ':' << field.name << ':';
|
1396 |
+
offset = field.offset + field.size;
|
1397 |
+
}
|
1398 |
+
if (itemsize > offset) {
|
1399 |
+
oss << (itemsize - offset) << 'x';
|
1400 |
+
}
|
1401 |
+
oss << '}';
|
1402 |
+
auto format_str = oss.str();
|
1403 |
+
|
1404 |
+
// Sanity check: verify that NumPy properly parses our buffer format string
|
1405 |
+
auto &api = npy_api::get();
|
1406 |
+
auto arr = array(buffer_info(nullptr, itemsize, format_str, 1));
|
1407 |
+
if (!api.PyArray_EquivTypes_(dtype_ptr, arr.dtype().ptr())) {
|
1408 |
+
pybind11_fail("NumPy: invalid buffer descriptor!");
|
1409 |
+
}
|
1410 |
+
|
1411 |
+
auto tindex = std::type_index(tinfo);
|
1412 |
+
numpy_internals.registered_dtypes[tindex] = {dtype_ptr, std::move(format_str)};
|
1413 |
+
get_internals().direct_conversions[tindex].push_back(direct_converter);
|
1414 |
+
}
|
1415 |
+
|
1416 |
+
template <typename T, typename SFINAE>
|
1417 |
+
struct npy_format_descriptor {
|
1418 |
+
static_assert(is_pod_struct<T>::value,
|
1419 |
+
"Attempt to use a non-POD or unimplemented POD type as a numpy dtype");
|
1420 |
+
|
1421 |
+
static constexpr auto name = make_caster<T>::name;
|
1422 |
+
|
1423 |
+
static pybind11::dtype dtype() { return reinterpret_borrow<pybind11::dtype>(dtype_ptr()); }
|
1424 |
+
|
1425 |
+
static std::string format() {
|
1426 |
+
static auto format_str = get_numpy_internals().get_type_info<T>(true)->format_str;
|
1427 |
+
return format_str;
|
1428 |
+
}
|
1429 |
+
|
1430 |
+
static void register_dtype(any_container<field_descriptor> fields) {
|
1431 |
+
register_structured_dtype(std::move(fields),
|
1432 |
+
typeid(typename std::remove_cv<T>::type),
|
1433 |
+
sizeof(T),
|
1434 |
+
&direct_converter);
|
1435 |
+
}
|
1436 |
+
|
1437 |
+
private:
|
1438 |
+
static PyObject *dtype_ptr() {
|
1439 |
+
static PyObject *ptr = get_numpy_internals().get_type_info<T>(true)->dtype_ptr;
|
1440 |
+
return ptr;
|
1441 |
+
}
|
1442 |
+
|
1443 |
+
static bool direct_converter(PyObject *obj, void *&value) {
|
1444 |
+
auto &api = npy_api::get();
|
1445 |
+
if (!PyObject_TypeCheck(obj, api.PyVoidArrType_Type_)) {
|
1446 |
+
return false;
|
1447 |
+
}
|
1448 |
+
if (auto descr = reinterpret_steal<object>(api.PyArray_DescrFromScalar_(obj))) {
|
1449 |
+
if (api.PyArray_EquivTypes_(dtype_ptr(), descr.ptr())) {
|
1450 |
+
value = ((PyVoidScalarObject_Proxy *) obj)->obval;
|
1451 |
+
return true;
|
1452 |
+
}
|
1453 |
+
}
|
1454 |
+
return false;
|
1455 |
+
}
|
1456 |
+
};
|
1457 |
+
|
1458 |
+
#ifdef __CLION_IDE__ // replace heavy macro with dummy code for the IDE (doesn't affect code)
|
1459 |
+
# define PYBIND11_NUMPY_DTYPE(Type, ...) ((void) 0)
|
1460 |
+
# define PYBIND11_NUMPY_DTYPE_EX(Type, ...) ((void) 0)
|
1461 |
+
#else
|
1462 |
+
|
1463 |
+
# define PYBIND11_FIELD_DESCRIPTOR_EX(T, Field, Name) \
|
1464 |
+
::pybind11::detail::field_descriptor { \
|
1465 |
+
Name, offsetof(T, Field), sizeof(decltype(std::declval<T>().Field)), \
|
1466 |
+
::pybind11::format_descriptor<decltype(std::declval<T>().Field)>::format(), \
|
1467 |
+
::pybind11::detail::npy_format_descriptor< \
|
1468 |
+
decltype(std::declval<T>().Field)>::dtype() \
|
1469 |
+
}
|
1470 |
+
|
1471 |
+
// Extract name, offset and format descriptor for a struct field
|
1472 |
+
# define PYBIND11_FIELD_DESCRIPTOR(T, Field) PYBIND11_FIELD_DESCRIPTOR_EX(T, Field, # Field)
|
1473 |
+
|
1474 |
+
// The main idea of this macro is borrowed from https://github.com/swansontec/map-macro
|
1475 |
+
// (C) William Swanson, Paul Fultz
|
1476 |
+
# define PYBIND11_EVAL0(...) __VA_ARGS__
|
1477 |
+
# define PYBIND11_EVAL1(...) PYBIND11_EVAL0(PYBIND11_EVAL0(PYBIND11_EVAL0(__VA_ARGS__)))
|
1478 |
+
# define PYBIND11_EVAL2(...) PYBIND11_EVAL1(PYBIND11_EVAL1(PYBIND11_EVAL1(__VA_ARGS__)))
|
1479 |
+
# define PYBIND11_EVAL3(...) PYBIND11_EVAL2(PYBIND11_EVAL2(PYBIND11_EVAL2(__VA_ARGS__)))
|
1480 |
+
# define PYBIND11_EVAL4(...) PYBIND11_EVAL3(PYBIND11_EVAL3(PYBIND11_EVAL3(__VA_ARGS__)))
|
1481 |
+
# define PYBIND11_EVAL(...) PYBIND11_EVAL4(PYBIND11_EVAL4(PYBIND11_EVAL4(__VA_ARGS__)))
|
1482 |
+
# define PYBIND11_MAP_END(...)
|
1483 |
+
# define PYBIND11_MAP_OUT
|
1484 |
+
# define PYBIND11_MAP_COMMA ,
|
1485 |
+
# define PYBIND11_MAP_GET_END() 0, PYBIND11_MAP_END
|
1486 |
+
# define PYBIND11_MAP_NEXT0(test, next, ...) next PYBIND11_MAP_OUT
|
1487 |
+
# define PYBIND11_MAP_NEXT1(test, next) PYBIND11_MAP_NEXT0(test, next, 0)
|
1488 |
+
# define PYBIND11_MAP_NEXT(test, next) PYBIND11_MAP_NEXT1(PYBIND11_MAP_GET_END test, next)
|
1489 |
+
# if defined(_MSC_VER) \
|
1490 |
+
&& !defined(__clang__) // MSVC is not as eager to expand macros, hence this workaround
|
1491 |
+
# define PYBIND11_MAP_LIST_NEXT1(test, next) \
|
1492 |
+
PYBIND11_EVAL0(PYBIND11_MAP_NEXT0(test, PYBIND11_MAP_COMMA next, 0))
|
1493 |
+
# else
|
1494 |
+
# define PYBIND11_MAP_LIST_NEXT1(test, next) \
|
1495 |
+
PYBIND11_MAP_NEXT0(test, PYBIND11_MAP_COMMA next, 0)
|
1496 |
+
# endif
|
1497 |
+
# define PYBIND11_MAP_LIST_NEXT(test, next) \
|
1498 |
+
PYBIND11_MAP_LIST_NEXT1(PYBIND11_MAP_GET_END test, next)
|
1499 |
+
# define PYBIND11_MAP_LIST0(f, t, x, peek, ...) \
|
1500 |
+
f(t, x) PYBIND11_MAP_LIST_NEXT(peek, PYBIND11_MAP_LIST1)(f, t, peek, __VA_ARGS__)
|
1501 |
+
# define PYBIND11_MAP_LIST1(f, t, x, peek, ...) \
|
1502 |
+
f(t, x) PYBIND11_MAP_LIST_NEXT(peek, PYBIND11_MAP_LIST0)(f, t, peek, __VA_ARGS__)
|
1503 |
+
// PYBIND11_MAP_LIST(f, t, a1, a2, ...) expands to f(t, a1), f(t, a2), ...
|
1504 |
+
# define PYBIND11_MAP_LIST(f, t, ...) \
|
1505 |
+
PYBIND11_EVAL(PYBIND11_MAP_LIST1(f, t, __VA_ARGS__, (), 0))
|
1506 |
+
|
1507 |
+
# define PYBIND11_NUMPY_DTYPE(Type, ...) \
|
1508 |
+
::pybind11::detail::npy_format_descriptor<Type>::register_dtype( \
|
1509 |
+
::std::vector<::pybind11::detail::field_descriptor>{ \
|
1510 |
+
PYBIND11_MAP_LIST(PYBIND11_FIELD_DESCRIPTOR, Type, __VA_ARGS__)})
|
1511 |
+
|
1512 |
+
# if defined(_MSC_VER) && !defined(__clang__)
|
1513 |
+
# define PYBIND11_MAP2_LIST_NEXT1(test, next) \
|
1514 |
+
PYBIND11_EVAL0(PYBIND11_MAP_NEXT0(test, PYBIND11_MAP_COMMA next, 0))
|
1515 |
+
# else
|
1516 |
+
# define PYBIND11_MAP2_LIST_NEXT1(test, next) \
|
1517 |
+
PYBIND11_MAP_NEXT0(test, PYBIND11_MAP_COMMA next, 0)
|
1518 |
+
# endif
|
1519 |
+
# define PYBIND11_MAP2_LIST_NEXT(test, next) \
|
1520 |
+
PYBIND11_MAP2_LIST_NEXT1(PYBIND11_MAP_GET_END test, next)
|
1521 |
+
# define PYBIND11_MAP2_LIST0(f, t, x1, x2, peek, ...) \
|
1522 |
+
f(t, x1, x2) PYBIND11_MAP2_LIST_NEXT(peek, PYBIND11_MAP2_LIST1)(f, t, peek, __VA_ARGS__)
|
1523 |
+
# define PYBIND11_MAP2_LIST1(f, t, x1, x2, peek, ...) \
|
1524 |
+
f(t, x1, x2) PYBIND11_MAP2_LIST_NEXT(peek, PYBIND11_MAP2_LIST0)(f, t, peek, __VA_ARGS__)
|
1525 |
+
// PYBIND11_MAP2_LIST(f, t, a1, a2, ...) expands to f(t, a1, a2), f(t, a3, a4), ...
|
1526 |
+
# define PYBIND11_MAP2_LIST(f, t, ...) \
|
1527 |
+
PYBIND11_EVAL(PYBIND11_MAP2_LIST1(f, t, __VA_ARGS__, (), 0))
|
1528 |
+
|
1529 |
+
# define PYBIND11_NUMPY_DTYPE_EX(Type, ...) \
|
1530 |
+
::pybind11::detail::npy_format_descriptor<Type>::register_dtype( \
|
1531 |
+
::std::vector<::pybind11::detail::field_descriptor>{ \
|
1532 |
+
PYBIND11_MAP2_LIST(PYBIND11_FIELD_DESCRIPTOR_EX, Type, __VA_ARGS__)})
|
1533 |
+
|
1534 |
+
#endif // __CLION_IDE__
|
1535 |
+
|
1536 |
+
class common_iterator {
|
1537 |
+
public:
|
1538 |
+
using container_type = std::vector<ssize_t>;
|
1539 |
+
using value_type = container_type::value_type;
|
1540 |
+
using size_type = container_type::size_type;
|
1541 |
+
|
1542 |
+
common_iterator() : m_strides() {}
|
1543 |
+
|
1544 |
+
common_iterator(void *ptr, const container_type &strides, const container_type &shape)
|
1545 |
+
: p_ptr(reinterpret_cast<char *>(ptr)), m_strides(strides.size()) {
|
1546 |
+
m_strides.back() = static_cast<value_type>(strides.back());
|
1547 |
+
for (size_type i = m_strides.size() - 1; i != 0; --i) {
|
1548 |
+
size_type j = i - 1;
|
1549 |
+
auto s = static_cast<value_type>(shape[i]);
|
1550 |
+
m_strides[j] = strides[j] + m_strides[i] - strides[i] * s;
|
1551 |
+
}
|
1552 |
+
}
|
1553 |
+
|
1554 |
+
void increment(size_type dim) { p_ptr += m_strides[dim]; }
|
1555 |
+
|
1556 |
+
void *data() const { return p_ptr; }
|
1557 |
+
|
1558 |
+
private:
|
1559 |
+
char *p_ptr{nullptr};
|
1560 |
+
container_type m_strides;
|
1561 |
+
};
|
1562 |
+
|
1563 |
+
template <size_t N>
|
1564 |
+
class multi_array_iterator {
|
1565 |
+
public:
|
1566 |
+
using container_type = std::vector<ssize_t>;
|
1567 |
+
|
1568 |
+
multi_array_iterator(const std::array<buffer_info, N> &buffers, const container_type &shape)
|
1569 |
+
: m_shape(shape.size()), m_index(shape.size(), 0), m_common_iterator() {
|
1570 |
+
|
1571 |
+
// Manual copy to avoid conversion warning if using std::copy
|
1572 |
+
for (size_t i = 0; i < shape.size(); ++i) {
|
1573 |
+
m_shape[i] = shape[i];
|
1574 |
+
}
|
1575 |
+
|
1576 |
+
container_type strides(shape.size());
|
1577 |
+
for (size_t i = 0; i < N; ++i) {
|
1578 |
+
init_common_iterator(buffers[i], shape, m_common_iterator[i], strides);
|
1579 |
+
}
|
1580 |
+
}
|
1581 |
+
|
1582 |
+
multi_array_iterator &operator++() {
|
1583 |
+
for (size_t j = m_index.size(); j != 0; --j) {
|
1584 |
+
size_t i = j - 1;
|
1585 |
+
if (++m_index[i] != m_shape[i]) {
|
1586 |
+
increment_common_iterator(i);
|
1587 |
+
break;
|
1588 |
+
}
|
1589 |
+
m_index[i] = 0;
|
1590 |
+
}
|
1591 |
+
return *this;
|
1592 |
+
}
|
1593 |
+
|
1594 |
+
template <size_t K, class T = void>
|
1595 |
+
T *data() const {
|
1596 |
+
return reinterpret_cast<T *>(m_common_iterator[K].data());
|
1597 |
+
}
|
1598 |
+
|
1599 |
+
private:
|
1600 |
+
using common_iter = common_iterator;
|
1601 |
+
|
1602 |
+
void init_common_iterator(const buffer_info &buffer,
|
1603 |
+
const container_type &shape,
|
1604 |
+
common_iter &iterator,
|
1605 |
+
container_type &strides) {
|
1606 |
+
auto buffer_shape_iter = buffer.shape.rbegin();
|
1607 |
+
auto buffer_strides_iter = buffer.strides.rbegin();
|
1608 |
+
auto shape_iter = shape.rbegin();
|
1609 |
+
auto strides_iter = strides.rbegin();
|
1610 |
+
|
1611 |
+
while (buffer_shape_iter != buffer.shape.rend()) {
|
1612 |
+
if (*shape_iter == *buffer_shape_iter) {
|
1613 |
+
*strides_iter = *buffer_strides_iter;
|
1614 |
+
} else {
|
1615 |
+
*strides_iter = 0;
|
1616 |
+
}
|
1617 |
+
|
1618 |
+
++buffer_shape_iter;
|
1619 |
+
++buffer_strides_iter;
|
1620 |
+
++shape_iter;
|
1621 |
+
++strides_iter;
|
1622 |
+
}
|
1623 |
+
|
1624 |
+
std::fill(strides_iter, strides.rend(), 0);
|
1625 |
+
iterator = common_iter(buffer.ptr, strides, shape);
|
1626 |
+
}
|
1627 |
+
|
1628 |
+
void increment_common_iterator(size_t dim) {
|
1629 |
+
for (auto &iter : m_common_iterator) {
|
1630 |
+
iter.increment(dim);
|
1631 |
+
}
|
1632 |
+
}
|
1633 |
+
|
1634 |
+
container_type m_shape;
|
1635 |
+
container_type m_index;
|
1636 |
+
std::array<common_iter, N> m_common_iterator;
|
1637 |
+
};
|
1638 |
+
|
1639 |
+
enum class broadcast_trivial { non_trivial, c_trivial, f_trivial };
|
1640 |
+
|
1641 |
+
// Populates the shape and number of dimensions for the set of buffers. Returns a
|
1642 |
+
// broadcast_trivial enum value indicating whether the broadcast is "trivial"--that is, has each
|
1643 |
+
// buffer being either a singleton or a full-size, C-contiguous (`c_trivial`) or Fortran-contiguous
|
1644 |
+
// (`f_trivial`) storage buffer; returns `non_trivial` otherwise.
|
1645 |
+
template <size_t N>
|
1646 |
+
broadcast_trivial
|
1647 |
+
broadcast(const std::array<buffer_info, N> &buffers, ssize_t &ndim, std::vector<ssize_t> &shape) {
|
1648 |
+
ndim = std::accumulate(
|
1649 |
+
buffers.begin(), buffers.end(), ssize_t(0), [](ssize_t res, const buffer_info &buf) {
|
1650 |
+
return std::max(res, buf.ndim);
|
1651 |
+
});
|
1652 |
+
|
1653 |
+
shape.clear();
|
1654 |
+
shape.resize((size_t) ndim, 1);
|
1655 |
+
|
1656 |
+
// Figure out the output size, and make sure all input arrays conform (i.e. are either size 1
|
1657 |
+
// or the full size).
|
1658 |
+
for (size_t i = 0; i < N; ++i) {
|
1659 |
+
auto res_iter = shape.rbegin();
|
1660 |
+
auto end = buffers[i].shape.rend();
|
1661 |
+
for (auto shape_iter = buffers[i].shape.rbegin(); shape_iter != end;
|
1662 |
+
++shape_iter, ++res_iter) {
|
1663 |
+
const auto &dim_size_in = *shape_iter;
|
1664 |
+
auto &dim_size_out = *res_iter;
|
1665 |
+
|
1666 |
+
// Each input dimension can either be 1 or `n`, but `n` values must match across
|
1667 |
+
// buffers
|
1668 |
+
if (dim_size_out == 1) {
|
1669 |
+
dim_size_out = dim_size_in;
|
1670 |
+
} else if (dim_size_in != 1 && dim_size_in != dim_size_out) {
|
1671 |
+
pybind11_fail("pybind11::vectorize: incompatible size/dimension of inputs!");
|
1672 |
+
}
|
1673 |
+
}
|
1674 |
+
}
|
1675 |
+
|
1676 |
+
bool trivial_broadcast_c = true;
|
1677 |
+
bool trivial_broadcast_f = true;
|
1678 |
+
for (size_t i = 0; i < N && (trivial_broadcast_c || trivial_broadcast_f); ++i) {
|
1679 |
+
if (buffers[i].size == 1) {
|
1680 |
+
continue;
|
1681 |
+
}
|
1682 |
+
|
1683 |
+
// Require the same number of dimensions:
|
1684 |
+
if (buffers[i].ndim != ndim) {
|
1685 |
+
return broadcast_trivial::non_trivial;
|
1686 |
+
}
|
1687 |
+
|
1688 |
+
// Require all dimensions be full-size:
|
1689 |
+
if (!std::equal(buffers[i].shape.cbegin(), buffers[i].shape.cend(), shape.cbegin())) {
|
1690 |
+
return broadcast_trivial::non_trivial;
|
1691 |
+
}
|
1692 |
+
|
1693 |
+
// Check for C contiguity (but only if previous inputs were also C contiguous)
|
1694 |
+
if (trivial_broadcast_c) {
|
1695 |
+
ssize_t expect_stride = buffers[i].itemsize;
|
1696 |
+
auto end = buffers[i].shape.crend();
|
1697 |
+
for (auto shape_iter = buffers[i].shape.crbegin(),
|
1698 |
+
stride_iter = buffers[i].strides.crbegin();
|
1699 |
+
trivial_broadcast_c && shape_iter != end;
|
1700 |
+
++shape_iter, ++stride_iter) {
|
1701 |
+
if (expect_stride == *stride_iter) {
|
1702 |
+
expect_stride *= *shape_iter;
|
1703 |
+
} else {
|
1704 |
+
trivial_broadcast_c = false;
|
1705 |
+
}
|
1706 |
+
}
|
1707 |
+
}
|
1708 |
+
|
1709 |
+
// Check for Fortran contiguity (if previous inputs were also F contiguous)
|
1710 |
+
if (trivial_broadcast_f) {
|
1711 |
+
ssize_t expect_stride = buffers[i].itemsize;
|
1712 |
+
auto end = buffers[i].shape.cend();
|
1713 |
+
for (auto shape_iter = buffers[i].shape.cbegin(),
|
1714 |
+
stride_iter = buffers[i].strides.cbegin();
|
1715 |
+
trivial_broadcast_f && shape_iter != end;
|
1716 |
+
++shape_iter, ++stride_iter) {
|
1717 |
+
if (expect_stride == *stride_iter) {
|
1718 |
+
expect_stride *= *shape_iter;
|
1719 |
+
} else {
|
1720 |
+
trivial_broadcast_f = false;
|
1721 |
+
}
|
1722 |
+
}
|
1723 |
+
}
|
1724 |
+
}
|
1725 |
+
|
1726 |
+
return trivial_broadcast_c ? broadcast_trivial::c_trivial
|
1727 |
+
: trivial_broadcast_f ? broadcast_trivial::f_trivial
|
1728 |
+
: broadcast_trivial::non_trivial;
|
1729 |
+
}
|
1730 |
+
|
1731 |
+
template <typename T>
|
1732 |
+
struct vectorize_arg {
|
1733 |
+
static_assert(!std::is_rvalue_reference<T>::value,
|
1734 |
+
"Functions with rvalue reference arguments cannot be vectorized");
|
1735 |
+
// The wrapped function gets called with this type:
|
1736 |
+
using call_type = remove_reference_t<T>;
|
1737 |
+
// Is this a vectorized argument?
|
1738 |
+
static constexpr bool vectorize
|
1739 |
+
= satisfies_any_of<call_type, std::is_arithmetic, is_complex, is_pod>::value
|
1740 |
+
&& satisfies_none_of<call_type,
|
1741 |
+
std::is_pointer,
|
1742 |
+
std::is_array,
|
1743 |
+
is_std_array,
|
1744 |
+
std::is_enum>::value
|
1745 |
+
&& (!std::is_reference<T>::value
|
1746 |
+
|| (std::is_lvalue_reference<T>::value && std::is_const<call_type>::value));
|
1747 |
+
// Accept this type: an array for vectorized types, otherwise the type as-is:
|
1748 |
+
using type = conditional_t<vectorize, array_t<remove_cv_t<call_type>, array::forcecast>, T>;
|
1749 |
+
};
|
1750 |
+
|
1751 |
+
// py::vectorize when a return type is present
|
1752 |
+
template <typename Func, typename Return, typename... Args>
|
1753 |
+
struct vectorize_returned_array {
|
1754 |
+
using Type = array_t<Return>;
|
1755 |
+
|
1756 |
+
static Type create(broadcast_trivial trivial, const std::vector<ssize_t> &shape) {
|
1757 |
+
if (trivial == broadcast_trivial::f_trivial) {
|
1758 |
+
return array_t<Return, array::f_style>(shape);
|
1759 |
+
}
|
1760 |
+
return array_t<Return>(shape);
|
1761 |
+
}
|
1762 |
+
|
1763 |
+
static Return *mutable_data(Type &array) { return array.mutable_data(); }
|
1764 |
+
|
1765 |
+
static Return call(Func &f, Args &...args) { return f(args...); }
|
1766 |
+
|
1767 |
+
static void call(Return *out, size_t i, Func &f, Args &...args) { out[i] = f(args...); }
|
1768 |
+
};
|
1769 |
+
|
1770 |
+
// py::vectorize when a return type is not present
|
1771 |
+
template <typename Func, typename... Args>
|
1772 |
+
struct vectorize_returned_array<Func, void, Args...> {
|
1773 |
+
using Type = none;
|
1774 |
+
|
1775 |
+
static Type create(broadcast_trivial, const std::vector<ssize_t> &) { return none(); }
|
1776 |
+
|
1777 |
+
static void *mutable_data(Type &) { return nullptr; }
|
1778 |
+
|
1779 |
+
static detail::void_type call(Func &f, Args &...args) {
|
1780 |
+
f(args...);
|
1781 |
+
return {};
|
1782 |
+
}
|
1783 |
+
|
1784 |
+
static void call(void *, size_t, Func &f, Args &...args) { f(args...); }
|
1785 |
+
};
|
1786 |
+
|
1787 |
+
template <typename Func, typename Return, typename... Args>
|
1788 |
+
struct vectorize_helper {
|
1789 |
+
|
1790 |
+
// NVCC for some reason breaks if NVectorized is private
|
1791 |
+
#ifdef __CUDACC__
|
1792 |
+
public:
|
1793 |
+
#else
|
1794 |
+
private:
|
1795 |
+
#endif
|
1796 |
+
|
1797 |
+
static constexpr size_t N = sizeof...(Args);
|
1798 |
+
static constexpr size_t NVectorized = constexpr_sum(vectorize_arg<Args>::vectorize...);
|
1799 |
+
static_assert(
|
1800 |
+
NVectorized >= 1,
|
1801 |
+
"pybind11::vectorize(...) requires a function with at least one vectorizable argument");
|
1802 |
+
|
1803 |
+
public:
|
1804 |
+
template <typename T,
|
1805 |
+
// SFINAE to prevent shadowing the copy constructor.
|
1806 |
+
typename = detail::enable_if_t<
|
1807 |
+
!std::is_same<vectorize_helper, typename std::decay<T>::type>::value>>
|
1808 |
+
explicit vectorize_helper(T &&f) : f(std::forward<T>(f)) {}
|
1809 |
+
|
1810 |
+
object operator()(typename vectorize_arg<Args>::type... args) {
|
1811 |
+
return run(args...,
|
1812 |
+
make_index_sequence<N>(),
|
1813 |
+
select_indices<vectorize_arg<Args>::vectorize...>(),
|
1814 |
+
make_index_sequence<NVectorized>());
|
1815 |
+
}
|
1816 |
+
|
1817 |
+
private:
|
1818 |
+
remove_reference_t<Func> f;
|
1819 |
+
|
1820 |
+
// Internal compiler error in MSVC 19.16.27025.1 (Visual Studio 2017 15.9.4), when compiling
|
1821 |
+
// with "/permissive-" flag when arg_call_types is manually inlined.
|
1822 |
+
using arg_call_types = std::tuple<typename vectorize_arg<Args>::call_type...>;
|
1823 |
+
template <size_t Index>
|
1824 |
+
using param_n_t = typename std::tuple_element<Index, arg_call_types>::type;
|
1825 |
+
|
1826 |
+
using returned_array = vectorize_returned_array<Func, Return, Args...>;
|
1827 |
+
|
1828 |
+
// Runs a vectorized function given arguments tuple and three index sequences:
|
1829 |
+
// - Index is the full set of 0 ... (N-1) argument indices;
|
1830 |
+
// - VIndex is the subset of argument indices with vectorized parameters, letting us access
|
1831 |
+
// vectorized arguments (anything not in this sequence is passed through)
|
1832 |
+
// - BIndex is a incremental sequence (beginning at 0) of the same size as VIndex, so that
|
1833 |
+
// we can store vectorized buffer_infos in an array (argument VIndex has its buffer at
|
1834 |
+
// index BIndex in the array).
|
1835 |
+
template <size_t... Index, size_t... VIndex, size_t... BIndex>
|
1836 |
+
object run(typename vectorize_arg<Args>::type &...args,
|
1837 |
+
index_sequence<Index...> i_seq,
|
1838 |
+
index_sequence<VIndex...> vi_seq,
|
1839 |
+
index_sequence<BIndex...> bi_seq) {
|
1840 |
+
|
1841 |
+
// Pointers to values the function was called with; the vectorized ones set here will start
|
1842 |
+
// out as array_t<T> pointers, but they will be changed them to T pointers before we make
|
1843 |
+
// call the wrapped function. Non-vectorized pointers are left as-is.
|
1844 |
+
std::array<void *, N> params{{&args...}};
|
1845 |
+
|
1846 |
+
// The array of `buffer_info`s of vectorized arguments:
|
1847 |
+
std::array<buffer_info, NVectorized> buffers{
|
1848 |
+
{reinterpret_cast<array *>(params[VIndex])->request()...}};
|
1849 |
+
|
1850 |
+
/* Determine dimensions parameters of output array */
|
1851 |
+
ssize_t nd = 0;
|
1852 |
+
std::vector<ssize_t> shape(0);
|
1853 |
+
auto trivial = broadcast(buffers, nd, shape);
|
1854 |
+
auto ndim = (size_t) nd;
|
1855 |
+
|
1856 |
+
size_t size
|
1857 |
+
= std::accumulate(shape.begin(), shape.end(), (size_t) 1, std::multiplies<size_t>());
|
1858 |
+
|
1859 |
+
// If all arguments are 0-dimension arrays (i.e. single values) return a plain value (i.e.
|
1860 |
+
// not wrapped in an array).
|
1861 |
+
if (size == 1 && ndim == 0) {
|
1862 |
+
PYBIND11_EXPAND_SIDE_EFFECTS(params[VIndex] = buffers[BIndex].ptr);
|
1863 |
+
return cast(
|
1864 |
+
returned_array::call(f, *reinterpret_cast<param_n_t<Index> *>(params[Index])...));
|
1865 |
+
}
|
1866 |
+
|
1867 |
+
auto result = returned_array::create(trivial, shape);
|
1868 |
+
|
1869 |
+
if (size == 0) {
|
1870 |
+
return std::move(result);
|
1871 |
+
}
|
1872 |
+
|
1873 |
+
/* Call the function */
|
1874 |
+
auto *mutable_data = returned_array::mutable_data(result);
|
1875 |
+
if (trivial == broadcast_trivial::non_trivial) {
|
1876 |
+
apply_broadcast(buffers, params, mutable_data, size, shape, i_seq, vi_seq, bi_seq);
|
1877 |
+
} else {
|
1878 |
+
apply_trivial(buffers, params, mutable_data, size, i_seq, vi_seq, bi_seq);
|
1879 |
+
}
|
1880 |
+
|
1881 |
+
return std::move(result);
|
1882 |
+
}
|
1883 |
+
|
1884 |
+
template <size_t... Index, size_t... VIndex, size_t... BIndex>
|
1885 |
+
void apply_trivial(std::array<buffer_info, NVectorized> &buffers,
|
1886 |
+
std::array<void *, N> ¶ms,
|
1887 |
+
Return *out,
|
1888 |
+
size_t size,
|
1889 |
+
index_sequence<Index...>,
|
1890 |
+
index_sequence<VIndex...>,
|
1891 |
+
index_sequence<BIndex...>) {
|
1892 |
+
|
1893 |
+
// Initialize an array of mutable byte references and sizes with references set to the
|
1894 |
+
// appropriate pointer in `params`; as we iterate, we'll increment each pointer by its size
|
1895 |
+
// (except for singletons, which get an increment of 0).
|
1896 |
+
std::array<std::pair<unsigned char *&, const size_t>, NVectorized> vecparams{
|
1897 |
+
{std::pair<unsigned char *&, const size_t>(
|
1898 |
+
reinterpret_cast<unsigned char *&>(params[VIndex] = buffers[BIndex].ptr),
|
1899 |
+
buffers[BIndex].size == 1 ? 0 : sizeof(param_n_t<VIndex>))...}};
|
1900 |
+
|
1901 |
+
for (size_t i = 0; i < size; ++i) {
|
1902 |
+
returned_array::call(
|
1903 |
+
out, i, f, *reinterpret_cast<param_n_t<Index> *>(params[Index])...);
|
1904 |
+
for (auto &x : vecparams) {
|
1905 |
+
x.first += x.second;
|
1906 |
+
}
|
1907 |
+
}
|
1908 |
+
}
|
1909 |
+
|
1910 |
+
template <size_t... Index, size_t... VIndex, size_t... BIndex>
|
1911 |
+
void apply_broadcast(std::array<buffer_info, NVectorized> &buffers,
|
1912 |
+
std::array<void *, N> ¶ms,
|
1913 |
+
Return *out,
|
1914 |
+
size_t size,
|
1915 |
+
const std::vector<ssize_t> &output_shape,
|
1916 |
+
index_sequence<Index...>,
|
1917 |
+
index_sequence<VIndex...>,
|
1918 |
+
index_sequence<BIndex...>) {
|
1919 |
+
|
1920 |
+
multi_array_iterator<NVectorized> input_iter(buffers, output_shape);
|
1921 |
+
|
1922 |
+
for (size_t i = 0; i < size; ++i, ++input_iter) {
|
1923 |
+
PYBIND11_EXPAND_SIDE_EFFECTS((params[VIndex] = input_iter.template data<BIndex>()));
|
1924 |
+
returned_array::call(
|
1925 |
+
out, i, f, *reinterpret_cast<param_n_t<Index> *>(std::get<Index>(params))...);
|
1926 |
+
}
|
1927 |
+
}
|
1928 |
+
};
|
1929 |
+
|
1930 |
+
template <typename Func, typename Return, typename... Args>
|
1931 |
+
vectorize_helper<Func, Return, Args...> vectorize_extractor(const Func &f, Return (*)(Args...)) {
|
1932 |
+
return detail::vectorize_helper<Func, Return, Args...>(f);
|
1933 |
+
}
|
1934 |
+
|
1935 |
+
template <typename T, int Flags>
|
1936 |
+
struct handle_type_name<array_t<T, Flags>> {
|
1937 |
+
static constexpr auto name
|
1938 |
+
= const_name("numpy.ndarray[") + npy_format_descriptor<T>::name + const_name("]");
|
1939 |
+
};
|
1940 |
+
|
1941 |
+
PYBIND11_NAMESPACE_END(detail)
|
1942 |
+
|
1943 |
+
// Vanilla pointer vectorizer:
|
1944 |
+
template <typename Return, typename... Args>
|
1945 |
+
detail::vectorize_helper<Return (*)(Args...), Return, Args...> vectorize(Return (*f)(Args...)) {
|
1946 |
+
return detail::vectorize_helper<Return (*)(Args...), Return, Args...>(f);
|
1947 |
+
}
|
1948 |
+
|
1949 |
+
// lambda vectorizer:
|
1950 |
+
template <typename Func, detail::enable_if_t<detail::is_lambda<Func>::value, int> = 0>
|
1951 |
+
auto vectorize(Func &&f)
|
1952 |
+
-> decltype(detail::vectorize_extractor(std::forward<Func>(f),
|
1953 |
+
(detail::function_signature_t<Func> *) nullptr)) {
|
1954 |
+
return detail::vectorize_extractor(std::forward<Func>(f),
|
1955 |
+
(detail::function_signature_t<Func> *) nullptr);
|
1956 |
+
}
|
1957 |
+
|
1958 |
+
// Vectorize a class method (non-const):
|
1959 |
+
template <typename Return,
|
1960 |
+
typename Class,
|
1961 |
+
typename... Args,
|
1962 |
+
typename Helper = detail::vectorize_helper<
|
1963 |
+
decltype(std::mem_fn(std::declval<Return (Class::*)(Args...)>())),
|
1964 |
+
Return,
|
1965 |
+
Class *,
|
1966 |
+
Args...>>
|
1967 |
+
Helper vectorize(Return (Class::*f)(Args...)) {
|
1968 |
+
return Helper(std::mem_fn(f));
|
1969 |
+
}
|
1970 |
+
|
1971 |
+
// Vectorize a class method (const):
|
1972 |
+
template <typename Return,
|
1973 |
+
typename Class,
|
1974 |
+
typename... Args,
|
1975 |
+
typename Helper = detail::vectorize_helper<
|
1976 |
+
decltype(std::mem_fn(std::declval<Return (Class::*)(Args...) const>())),
|
1977 |
+
Return,
|
1978 |
+
const Class *,
|
1979 |
+
Args...>>
|
1980 |
+
Helper vectorize(Return (Class::*f)(Args...) const) {
|
1981 |
+
return Helper(std::mem_fn(f));
|
1982 |
+
}
|
1983 |
+
|
1984 |
+
PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)
|
third-party/DPVO/DPViewer/pybind11/include/pybind11/operators.h
ADDED
@@ -0,0 +1,201 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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 |
+
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
|
15 |
+
PYBIND11_NAMESPACE_BEGIN(detail)
|
16 |
+
|
17 |
+
/// Enumeration with all supported operator types
|
18 |
+
enum op_id : int {
|
19 |
+
op_add,
|
20 |
+
op_sub,
|
21 |
+
op_mul,
|
22 |
+
op_div,
|
23 |
+
op_mod,
|
24 |
+
op_divmod,
|
25 |
+
op_pow,
|
26 |
+
op_lshift,
|
27 |
+
op_rshift,
|
28 |
+
op_and,
|
29 |
+
op_xor,
|
30 |
+
op_or,
|
31 |
+
op_neg,
|
32 |
+
op_pos,
|
33 |
+
op_abs,
|
34 |
+
op_invert,
|
35 |
+
op_int,
|
36 |
+
op_long,
|
37 |
+
op_float,
|
38 |
+
op_str,
|
39 |
+
op_cmp,
|
40 |
+
op_gt,
|
41 |
+
op_ge,
|
42 |
+
op_lt,
|
43 |
+
op_le,
|
44 |
+
op_eq,
|
45 |
+
op_ne,
|
46 |
+
op_iadd,
|
47 |
+
op_isub,
|
48 |
+
op_imul,
|
49 |
+
op_idiv,
|
50 |
+
op_imod,
|
51 |
+
op_ilshift,
|
52 |
+
op_irshift,
|
53 |
+
op_iand,
|
54 |
+
op_ixor,
|
55 |
+
op_ior,
|
56 |
+
op_complex,
|
57 |
+
op_bool,
|
58 |
+
op_nonzero,
|
59 |
+
op_repr,
|
60 |
+
op_truediv,
|
61 |
+
op_itruediv,
|
62 |
+
op_hash
|
63 |
+
};
|
64 |
+
|
65 |
+
enum op_type : int {
|
66 |
+
op_l, /* base type on left */
|
67 |
+
op_r, /* base type on right */
|
68 |
+
op_u /* unary operator */
|
69 |
+
};
|
70 |
+
|
71 |
+
struct self_t {};
|
72 |
+
static const self_t self = self_t();
|
73 |
+
|
74 |
+
/// Type for an unused type slot
|
75 |
+
struct undefined_t {};
|
76 |
+
|
77 |
+
/// Don't warn about an unused variable
|
78 |
+
inline self_t __self() { return self; }
|
79 |
+
|
80 |
+
/// base template of operator implementations
|
81 |
+
template <op_id, op_type, typename B, typename L, typename R>
|
82 |
+
struct op_impl {};
|
83 |
+
|
84 |
+
/// Operator implementation generator
|
85 |
+
template <op_id id, op_type ot, typename L, typename R>
|
86 |
+
struct op_ {
|
87 |
+
template <typename Class, typename... Extra>
|
88 |
+
void execute(Class &cl, const Extra &...extra) const {
|
89 |
+
using Base = typename Class::type;
|
90 |
+
using L_type = conditional_t<std::is_same<L, self_t>::value, Base, L>;
|
91 |
+
using R_type = conditional_t<std::is_same<R, self_t>::value, Base, R>;
|
92 |
+
using op = op_impl<id, ot, Base, L_type, R_type>;
|
93 |
+
cl.def(op::name(), &op::execute, is_operator(), extra...);
|
94 |
+
}
|
95 |
+
template <typename Class, typename... Extra>
|
96 |
+
void execute_cast(Class &cl, const Extra &...extra) const {
|
97 |
+
using Base = typename Class::type;
|
98 |
+
using L_type = conditional_t<std::is_same<L, self_t>::value, Base, L>;
|
99 |
+
using R_type = conditional_t<std::is_same<R, self_t>::value, Base, R>;
|
100 |
+
using op = op_impl<id, ot, Base, L_type, R_type>;
|
101 |
+
cl.def(op::name(), &op::execute_cast, is_operator(), extra...);
|
102 |
+
}
|
103 |
+
};
|
104 |
+
|
105 |
+
#define PYBIND11_BINARY_OPERATOR(id, rid, op, expr) \
|
106 |
+
template <typename B, typename L, typename R> \
|
107 |
+
struct op_impl<op_##id, op_l, B, L, R> { \
|
108 |
+
static char const *name() { return "__" #id "__"; } \
|
109 |
+
static auto execute(const L &l, const R &r) -> decltype(expr) { return (expr); } \
|
110 |
+
static B execute_cast(const L &l, const R &r) { return B(expr); } \
|
111 |
+
}; \
|
112 |
+
template <typename B, typename L, typename R> \
|
113 |
+
struct op_impl<op_##id, op_r, B, L, R> { \
|
114 |
+
static char const *name() { return "__" #rid "__"; } \
|
115 |
+
static auto execute(const R &r, const L &l) -> decltype(expr) { return (expr); } \
|
116 |
+
static B execute_cast(const R &r, const L &l) { return B(expr); } \
|
117 |
+
}; \
|
118 |
+
inline op_<op_##id, op_l, self_t, self_t> op(const self_t &, const self_t &) { \
|
119 |
+
return op_<op_##id, op_l, self_t, self_t>(); \
|
120 |
+
} \
|
121 |
+
template <typename T> \
|
122 |
+
op_<op_##id, op_l, self_t, T> op(const self_t &, const T &) { \
|
123 |
+
return op_<op_##id, op_l, self_t, T>(); \
|
124 |
+
} \
|
125 |
+
template <typename T> \
|
126 |
+
op_<op_##id, op_r, T, self_t> op(const T &, const self_t &) { \
|
127 |
+
return op_<op_##id, op_r, T, self_t>(); \
|
128 |
+
}
|
129 |
+
|
130 |
+
#define PYBIND11_INPLACE_OPERATOR(id, op, expr) \
|
131 |
+
template <typename B, typename L, typename R> \
|
132 |
+
struct op_impl<op_##id, op_l, B, L, R> { \
|
133 |
+
static char const *name() { return "__" #id "__"; } \
|
134 |
+
static auto execute(L &l, const R &r) -> decltype(expr) { return expr; } \
|
135 |
+
static B execute_cast(L &l, const R &r) { return B(expr); } \
|
136 |
+
}; \
|
137 |
+
template <typename T> \
|
138 |
+
op_<op_##id, op_l, self_t, T> op(const self_t &, const T &) { \
|
139 |
+
return op_<op_##id, op_l, self_t, T>(); \
|
140 |
+
}
|
141 |
+
|
142 |
+
#define PYBIND11_UNARY_OPERATOR(id, op, expr) \
|
143 |
+
template <typename B, typename L> \
|
144 |
+
struct op_impl<op_##id, op_u, B, L, undefined_t> { \
|
145 |
+
static char const *name() { return "__" #id "__"; } \
|
146 |
+
static auto execute(const L &l) -> decltype(expr) { return expr; } \
|
147 |
+
static B execute_cast(const L &l) { return B(expr); } \
|
148 |
+
}; \
|
149 |
+
inline op_<op_##id, op_u, self_t, undefined_t> op(const self_t &) { \
|
150 |
+
return op_<op_##id, op_u, self_t, undefined_t>(); \
|
151 |
+
}
|
152 |
+
|
153 |
+
PYBIND11_BINARY_OPERATOR(sub, rsub, operator-, l - r)
|
154 |
+
PYBIND11_BINARY_OPERATOR(add, radd, operator+, l + r)
|
155 |
+
PYBIND11_BINARY_OPERATOR(mul, rmul, operator*, l *r)
|
156 |
+
PYBIND11_BINARY_OPERATOR(truediv, rtruediv, operator/, l / r)
|
157 |
+
PYBIND11_BINARY_OPERATOR(mod, rmod, operator%, l % r)
|
158 |
+
PYBIND11_BINARY_OPERATOR(lshift, rlshift, operator<<, l << r)
|
159 |
+
PYBIND11_BINARY_OPERATOR(rshift, rrshift, operator>>, l >> r)
|
160 |
+
PYBIND11_BINARY_OPERATOR(and, rand, operator&, l &r)
|
161 |
+
PYBIND11_BINARY_OPERATOR(xor, rxor, operator^, l ^ r)
|
162 |
+
PYBIND11_BINARY_OPERATOR(eq, eq, operator==, l == r)
|
163 |
+
PYBIND11_BINARY_OPERATOR(ne, ne, operator!=, l != r)
|
164 |
+
PYBIND11_BINARY_OPERATOR(or, ror, operator|, l | r)
|
165 |
+
PYBIND11_BINARY_OPERATOR(gt, lt, operator>, l > r)
|
166 |
+
PYBIND11_BINARY_OPERATOR(ge, le, operator>=, l >= r)
|
167 |
+
PYBIND11_BINARY_OPERATOR(lt, gt, operator<, l < r)
|
168 |
+
PYBIND11_BINARY_OPERATOR(le, ge, operator<=, l <= r)
|
169 |
+
// PYBIND11_BINARY_OPERATOR(pow, rpow, pow, std::pow(l, r))
|
170 |
+
PYBIND11_INPLACE_OPERATOR(iadd, operator+=, l += r)
|
171 |
+
PYBIND11_INPLACE_OPERATOR(isub, operator-=, l -= r)
|
172 |
+
PYBIND11_INPLACE_OPERATOR(imul, operator*=, l *= r)
|
173 |
+
PYBIND11_INPLACE_OPERATOR(itruediv, operator/=, l /= r)
|
174 |
+
PYBIND11_INPLACE_OPERATOR(imod, operator%=, l %= r)
|
175 |
+
PYBIND11_INPLACE_OPERATOR(ilshift, operator<<=, l <<= r)
|
176 |
+
PYBIND11_INPLACE_OPERATOR(irshift, operator>>=, l >>= r)
|
177 |
+
PYBIND11_INPLACE_OPERATOR(iand, operator&=, l &= r)
|
178 |
+
PYBIND11_INPLACE_OPERATOR(ixor, operator^=, l ^= r)
|
179 |
+
PYBIND11_INPLACE_OPERATOR(ior, operator|=, l |= r)
|
180 |
+
PYBIND11_UNARY_OPERATOR(neg, operator-, -l)
|
181 |
+
PYBIND11_UNARY_OPERATOR(pos, operator+, +l)
|
182 |
+
// WARNING: This usage of `abs` should only be done for existing STL overloads.
|
183 |
+
// Adding overloads directly in to the `std::` namespace is advised against:
|
184 |
+
// https://en.cppreference.com/w/cpp/language/extending_std
|
185 |
+
PYBIND11_UNARY_OPERATOR(abs, abs, std::abs(l))
|
186 |
+
PYBIND11_UNARY_OPERATOR(hash, hash, std::hash<L>()(l))
|
187 |
+
PYBIND11_UNARY_OPERATOR(invert, operator~, (~l))
|
188 |
+
PYBIND11_UNARY_OPERATOR(bool, operator!, !!l)
|
189 |
+
PYBIND11_UNARY_OPERATOR(int, int_, (int) l)
|
190 |
+
PYBIND11_UNARY_OPERATOR(float, float_, (double) l)
|
191 |
+
|
192 |
+
#undef PYBIND11_BINARY_OPERATOR
|
193 |
+
#undef PYBIND11_INPLACE_OPERATOR
|
194 |
+
#undef PYBIND11_UNARY_OPERATOR
|
195 |
+
PYBIND11_NAMESPACE_END(detail)
|
196 |
+
|
197 |
+
using detail::self;
|
198 |
+
// Add named operators so that they are accessible via `py::`.
|
199 |
+
using detail::hash;
|
200 |
+
|
201 |
+
PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)
|
third-party/DPVO/DPViewer/pybind11/include/pybind11/options.h
ADDED
@@ -0,0 +1,76 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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 |
+
// Default RAII constructor, which leaves settings as they currently are.
|
19 |
+
options() : previous_state(global_state()) {}
|
20 |
+
|
21 |
+
// Class is non-copyable.
|
22 |
+
options(const options &) = delete;
|
23 |
+
options &operator=(const options &) = delete;
|
24 |
+
|
25 |
+
// Destructor, which restores settings that were in effect before.
|
26 |
+
~options() { global_state() = previous_state; }
|
27 |
+
|
28 |
+
// Setter methods (affect the global state):
|
29 |
+
|
30 |
+
options &disable_user_defined_docstrings() & {
|
31 |
+
global_state().show_user_defined_docstrings = false;
|
32 |
+
return *this;
|
33 |
+
}
|
34 |
+
|
35 |
+
options &enable_user_defined_docstrings() & {
|
36 |
+
global_state().show_user_defined_docstrings = true;
|
37 |
+
return *this;
|
38 |
+
}
|
39 |
+
|
40 |
+
options &disable_function_signatures() & {
|
41 |
+
global_state().show_function_signatures = false;
|
42 |
+
return *this;
|
43 |
+
}
|
44 |
+
|
45 |
+
options &enable_function_signatures() & {
|
46 |
+
global_state().show_function_signatures = true;
|
47 |
+
return *this;
|
48 |
+
}
|
49 |
+
|
50 |
+
// Getter methods (return the global state):
|
51 |
+
|
52 |
+
static bool show_user_defined_docstrings() {
|
53 |
+
return global_state().show_user_defined_docstrings;
|
54 |
+
}
|
55 |
+
|
56 |
+
static bool show_function_signatures() { return global_state().show_function_signatures; }
|
57 |
+
|
58 |
+
// This type is not meant to be allocated on the heap.
|
59 |
+
void *operator new(size_t) = delete;
|
60 |
+
|
61 |
+
private:
|
62 |
+
struct state {
|
63 |
+
bool show_user_defined_docstrings = true; //< Include user-supplied texts in docstrings.
|
64 |
+
bool show_function_signatures = true; //< Include auto-generated function signatures
|
65 |
+
// in docstrings.
|
66 |
+
};
|
67 |
+
|
68 |
+
static state &global_state() {
|
69 |
+
static state instance;
|
70 |
+
return instance;
|
71 |
+
}
|
72 |
+
|
73 |
+
state previous_state;
|
74 |
+
};
|
75 |
+
|
76 |
+
PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)
|
third-party/DPVO/DPViewer/pybind11/include/pybind11/pybind11.h
ADDED
The diff for this file is too large to render.
See raw diff
|
|
third-party/DPVO/DPViewer/pybind11/include/pybind11/pytypes.h
ADDED
@@ -0,0 +1,2373 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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 |
+
|
15 |
+
#include <assert.h>
|
16 |
+
#include <cstddef>
|
17 |
+
#include <exception>
|
18 |
+
#include <frameobject.h>
|
19 |
+
#include <iterator>
|
20 |
+
#include <memory>
|
21 |
+
#include <string>
|
22 |
+
#include <type_traits>
|
23 |
+
#include <typeinfo>
|
24 |
+
#include <utility>
|
25 |
+
|
26 |
+
#if defined(PYBIND11_HAS_OPTIONAL)
|
27 |
+
# include <optional>
|
28 |
+
#endif
|
29 |
+
|
30 |
+
#ifdef PYBIND11_HAS_STRING_VIEW
|
31 |
+
# include <string_view>
|
32 |
+
#endif
|
33 |
+
|
34 |
+
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
|
35 |
+
|
36 |
+
/* A few forward declarations */
|
37 |
+
class handle;
|
38 |
+
class object;
|
39 |
+
class str;
|
40 |
+
class iterator;
|
41 |
+
class type;
|
42 |
+
struct arg;
|
43 |
+
struct arg_v;
|
44 |
+
|
45 |
+
PYBIND11_NAMESPACE_BEGIN(detail)
|
46 |
+
class args_proxy;
|
47 |
+
bool isinstance_generic(handle obj, const std::type_info &tp);
|
48 |
+
|
49 |
+
// Accessor forward declarations
|
50 |
+
template <typename Policy>
|
51 |
+
class accessor;
|
52 |
+
namespace accessor_policies {
|
53 |
+
struct obj_attr;
|
54 |
+
struct str_attr;
|
55 |
+
struct generic_item;
|
56 |
+
struct sequence_item;
|
57 |
+
struct list_item;
|
58 |
+
struct tuple_item;
|
59 |
+
} // namespace accessor_policies
|
60 |
+
using obj_attr_accessor = accessor<accessor_policies::obj_attr>;
|
61 |
+
using str_attr_accessor = accessor<accessor_policies::str_attr>;
|
62 |
+
using item_accessor = accessor<accessor_policies::generic_item>;
|
63 |
+
using sequence_accessor = accessor<accessor_policies::sequence_item>;
|
64 |
+
using list_accessor = accessor<accessor_policies::list_item>;
|
65 |
+
using tuple_accessor = accessor<accessor_policies::tuple_item>;
|
66 |
+
|
67 |
+
/// Tag and check to identify a class which implements the Python object API
|
68 |
+
class pyobject_tag {};
|
69 |
+
template <typename T>
|
70 |
+
using is_pyobject = std::is_base_of<pyobject_tag, remove_reference_t<T>>;
|
71 |
+
|
72 |
+
/** \rst
|
73 |
+
A mixin class which adds common functions to `handle`, `object` and various accessors.
|
74 |
+
The only requirement for `Derived` is to implement ``PyObject *Derived::ptr() const``.
|
75 |
+
\endrst */
|
76 |
+
template <typename Derived>
|
77 |
+
class object_api : public pyobject_tag {
|
78 |
+
const Derived &derived() const { return static_cast<const Derived &>(*this); }
|
79 |
+
|
80 |
+
public:
|
81 |
+
/** \rst
|
82 |
+
Return an iterator equivalent to calling ``iter()`` in Python. The object
|
83 |
+
must be a collection which supports the iteration protocol.
|
84 |
+
\endrst */
|
85 |
+
iterator begin() const;
|
86 |
+
/// Return a sentinel which ends iteration.
|
87 |
+
iterator end() const;
|
88 |
+
|
89 |
+
/** \rst
|
90 |
+
Return an internal functor to invoke the object's sequence protocol. Casting
|
91 |
+
the returned ``detail::item_accessor`` instance to a `handle` or `object`
|
92 |
+
subclass causes a corresponding call to ``__getitem__``. Assigning a `handle`
|
93 |
+
or `object` subclass causes a call to ``__setitem__``.
|
94 |
+
\endrst */
|
95 |
+
item_accessor operator[](handle key) const;
|
96 |
+
/// See above (the only difference is that the key's reference is stolen)
|
97 |
+
item_accessor operator[](object &&key) const;
|
98 |
+
/// See above (the only difference is that the key is provided as a string literal)
|
99 |
+
item_accessor operator[](const char *key) const;
|
100 |
+
|
101 |
+
/** \rst
|
102 |
+
Return an internal functor to access the object's attributes. Casting the
|
103 |
+
returned ``detail::obj_attr_accessor`` instance to a `handle` or `object`
|
104 |
+
subclass causes a corresponding call to ``getattr``. Assigning a `handle`
|
105 |
+
or `object` subclass causes a call to ``setattr``.
|
106 |
+
\endrst */
|
107 |
+
obj_attr_accessor attr(handle key) const;
|
108 |
+
/// See above (the only difference is that the key's reference is stolen)
|
109 |
+
obj_attr_accessor attr(object &&key) const;
|
110 |
+
/// See above (the only difference is that the key is provided as a string literal)
|
111 |
+
str_attr_accessor attr(const char *key) const;
|
112 |
+
|
113 |
+
/** \rst
|
114 |
+
Matches * unpacking in Python, e.g. to unpack arguments out of a ``tuple``
|
115 |
+
or ``list`` for a function call. Applying another * to the result yields
|
116 |
+
** unpacking, e.g. to unpack a dict as function keyword arguments.
|
117 |
+
See :ref:`calling_python_functions`.
|
118 |
+
\endrst */
|
119 |
+
args_proxy operator*() const;
|
120 |
+
|
121 |
+
/// Check if the given item is contained within this object, i.e. ``item in obj``.
|
122 |
+
template <typename T>
|
123 |
+
bool contains(T &&item) const;
|
124 |
+
|
125 |
+
/** \rst
|
126 |
+
Assuming the Python object is a function or implements the ``__call__``
|
127 |
+
protocol, ``operator()`` invokes the underlying function, passing an
|
128 |
+
arbitrary set of parameters. The result is returned as a `object` and
|
129 |
+
may need to be converted back into a Python object using `handle::cast()`.
|
130 |
+
|
131 |
+
When some of the arguments cannot be converted to Python objects, the
|
132 |
+
function will throw a `cast_error` exception. When the Python function
|
133 |
+
call fails, a `error_already_set` exception is thrown.
|
134 |
+
\endrst */
|
135 |
+
template <return_value_policy policy = return_value_policy::automatic_reference,
|
136 |
+
typename... Args>
|
137 |
+
object operator()(Args &&...args) const;
|
138 |
+
template <return_value_policy policy = return_value_policy::automatic_reference,
|
139 |
+
typename... Args>
|
140 |
+
PYBIND11_DEPRECATED("call(...) was deprecated in favor of operator()(...)")
|
141 |
+
object call(Args &&...args) const;
|
142 |
+
|
143 |
+
/// Equivalent to ``obj is other`` in Python.
|
144 |
+
bool is(object_api const &other) const { return derived().ptr() == other.derived().ptr(); }
|
145 |
+
/// Equivalent to ``obj is None`` in Python.
|
146 |
+
bool is_none() const { return derived().ptr() == Py_None; }
|
147 |
+
/// Equivalent to obj == other in Python
|
148 |
+
bool equal(object_api const &other) const { return rich_compare(other, Py_EQ); }
|
149 |
+
bool not_equal(object_api const &other) const { return rich_compare(other, Py_NE); }
|
150 |
+
bool operator<(object_api const &other) const { return rich_compare(other, Py_LT); }
|
151 |
+
bool operator<=(object_api const &other) const { return rich_compare(other, Py_LE); }
|
152 |
+
bool operator>(object_api const &other) const { return rich_compare(other, Py_GT); }
|
153 |
+
bool operator>=(object_api const &other) const { return rich_compare(other, Py_GE); }
|
154 |
+
|
155 |
+
object operator-() const;
|
156 |
+
object operator~() const;
|
157 |
+
object operator+(object_api const &other) const;
|
158 |
+
object operator+=(object_api const &other) const;
|
159 |
+
object operator-(object_api const &other) const;
|
160 |
+
object operator-=(object_api const &other) const;
|
161 |
+
object operator*(object_api const &other) const;
|
162 |
+
object operator*=(object_api const &other) const;
|
163 |
+
object operator/(object_api const &other) const;
|
164 |
+
object operator/=(object_api const &other) const;
|
165 |
+
object operator|(object_api const &other) const;
|
166 |
+
object operator|=(object_api const &other) const;
|
167 |
+
object operator&(object_api const &other) const;
|
168 |
+
object operator&=(object_api const &other) const;
|
169 |
+
object operator^(object_api const &other) const;
|
170 |
+
object operator^=(object_api const &other) const;
|
171 |
+
object operator<<(object_api const &other) const;
|
172 |
+
object operator<<=(object_api const &other) const;
|
173 |
+
object operator>>(object_api const &other) const;
|
174 |
+
object operator>>=(object_api const &other) const;
|
175 |
+
|
176 |
+
PYBIND11_DEPRECATED("Use py::str(obj) instead")
|
177 |
+
pybind11::str str() const;
|
178 |
+
|
179 |
+
/// Get or set the object's docstring, i.e. ``obj.__doc__``.
|
180 |
+
str_attr_accessor doc() const;
|
181 |
+
|
182 |
+
/// Return the object's current reference count
|
183 |
+
int ref_count() const { return static_cast<int>(Py_REFCNT(derived().ptr())); }
|
184 |
+
|
185 |
+
// TODO PYBIND11_DEPRECATED(
|
186 |
+
// "Call py::type::handle_of(h) or py::type::of(h) instead of h.get_type()")
|
187 |
+
handle get_type() const;
|
188 |
+
|
189 |
+
private:
|
190 |
+
bool rich_compare(object_api const &other, int value) const;
|
191 |
+
};
|
192 |
+
|
193 |
+
PYBIND11_NAMESPACE_END(detail)
|
194 |
+
|
195 |
+
#if !defined(PYBIND11_HANDLE_REF_DEBUG) && !defined(NDEBUG)
|
196 |
+
# define PYBIND11_HANDLE_REF_DEBUG
|
197 |
+
#endif
|
198 |
+
|
199 |
+
/** \rst
|
200 |
+
Holds a reference to a Python object (no reference counting)
|
201 |
+
|
202 |
+
The `handle` class is a thin wrapper around an arbitrary Python object (i.e. a
|
203 |
+
``PyObject *`` in Python's C API). It does not perform any automatic reference
|
204 |
+
counting and merely provides a basic C++ interface to various Python API functions.
|
205 |
+
|
206 |
+
.. seealso::
|
207 |
+
The `object` class inherits from `handle` and adds automatic reference
|
208 |
+
counting features.
|
209 |
+
\endrst */
|
210 |
+
class handle : public detail::object_api<handle> {
|
211 |
+
public:
|
212 |
+
/// The default constructor creates a handle with a ``nullptr``-valued pointer
|
213 |
+
handle() = default;
|
214 |
+
/// Creates a ``handle`` from the given raw Python object pointer
|
215 |
+
// NOLINTNEXTLINE(google-explicit-constructor)
|
216 |
+
handle(PyObject *ptr) : m_ptr(ptr) {} // Allow implicit conversion from PyObject*
|
217 |
+
|
218 |
+
/// Return the underlying ``PyObject *`` pointer
|
219 |
+
PyObject *ptr() const { return m_ptr; }
|
220 |
+
PyObject *&ptr() { return m_ptr; }
|
221 |
+
|
222 |
+
/** \rst
|
223 |
+
Manually increase the reference count of the Python object. Usually, it is
|
224 |
+
preferable to use the `object` class which derives from `handle` and calls
|
225 |
+
this function automatically. Returns a reference to itself.
|
226 |
+
\endrst */
|
227 |
+
const handle &inc_ref() const & {
|
228 |
+
#ifdef PYBIND11_HANDLE_REF_DEBUG
|
229 |
+
inc_ref_counter(1);
|
230 |
+
#endif
|
231 |
+
Py_XINCREF(m_ptr);
|
232 |
+
return *this;
|
233 |
+
}
|
234 |
+
|
235 |
+
/** \rst
|
236 |
+
Manually decrease the reference count of the Python object. Usually, it is
|
237 |
+
preferable to use the `object` class which derives from `handle` and calls
|
238 |
+
this function automatically. Returns a reference to itself.
|
239 |
+
\endrst */
|
240 |
+
const handle &dec_ref() const & {
|
241 |
+
Py_XDECREF(m_ptr);
|
242 |
+
return *this;
|
243 |
+
}
|
244 |
+
|
245 |
+
/** \rst
|
246 |
+
Attempt to cast the Python object into the given C++ type. A `cast_error`
|
247 |
+
will be throw upon failure.
|
248 |
+
\endrst */
|
249 |
+
template <typename T>
|
250 |
+
T cast() const;
|
251 |
+
/// Return ``true`` when the `handle` wraps a valid Python object
|
252 |
+
explicit operator bool() const { return m_ptr != nullptr; }
|
253 |
+
/** \rst
|
254 |
+
Deprecated: Check that the underlying pointers are the same.
|
255 |
+
Equivalent to ``obj1 is obj2`` in Python.
|
256 |
+
\endrst */
|
257 |
+
PYBIND11_DEPRECATED("Use obj1.is(obj2) instead")
|
258 |
+
bool operator==(const handle &h) const { return m_ptr == h.m_ptr; }
|
259 |
+
PYBIND11_DEPRECATED("Use !obj1.is(obj2) instead")
|
260 |
+
bool operator!=(const handle &h) const { return m_ptr != h.m_ptr; }
|
261 |
+
PYBIND11_DEPRECATED("Use handle::operator bool() instead")
|
262 |
+
bool check() const { return m_ptr != nullptr; }
|
263 |
+
|
264 |
+
protected:
|
265 |
+
PyObject *m_ptr = nullptr;
|
266 |
+
|
267 |
+
#ifdef PYBIND11_HANDLE_REF_DEBUG
|
268 |
+
private:
|
269 |
+
static std::size_t inc_ref_counter(std::size_t add) {
|
270 |
+
thread_local std::size_t counter = 0;
|
271 |
+
counter += add;
|
272 |
+
return counter;
|
273 |
+
}
|
274 |
+
|
275 |
+
public:
|
276 |
+
static std::size_t inc_ref_counter() { return inc_ref_counter(0); }
|
277 |
+
#endif
|
278 |
+
};
|
279 |
+
|
280 |
+
/** \rst
|
281 |
+
Holds a reference to a Python object (with reference counting)
|
282 |
+
|
283 |
+
Like `handle`, the `object` class is a thin wrapper around an arbitrary Python
|
284 |
+
object (i.e. a ``PyObject *`` in Python's C API). In contrast to `handle`, it
|
285 |
+
optionally increases the object's reference count upon construction, and it
|
286 |
+
*always* decreases the reference count when the `object` instance goes out of
|
287 |
+
scope and is destructed. When using `object` instances consistently, it is much
|
288 |
+
easier to get reference counting right at the first attempt.
|
289 |
+
\endrst */
|
290 |
+
class object : public handle {
|
291 |
+
public:
|
292 |
+
object() = default;
|
293 |
+
PYBIND11_DEPRECATED("Use reinterpret_borrow<object>() or reinterpret_steal<object>()")
|
294 |
+
object(handle h, bool is_borrowed) : handle(h) {
|
295 |
+
if (is_borrowed) {
|
296 |
+
inc_ref();
|
297 |
+
}
|
298 |
+
}
|
299 |
+
/// Copy constructor; always increases the reference count
|
300 |
+
object(const object &o) : handle(o) { inc_ref(); }
|
301 |
+
/// Move constructor; steals the object from ``other`` and preserves its reference count
|
302 |
+
object(object &&other) noexcept : handle(other) { other.m_ptr = nullptr; }
|
303 |
+
/// Destructor; automatically calls `handle::dec_ref()`
|
304 |
+
~object() { dec_ref(); }
|
305 |
+
|
306 |
+
/** \rst
|
307 |
+
Resets the internal pointer to ``nullptr`` without decreasing the
|
308 |
+
object's reference count. The function returns a raw handle to the original
|
309 |
+
Python object.
|
310 |
+
\endrst */
|
311 |
+
handle release() {
|
312 |
+
PyObject *tmp = m_ptr;
|
313 |
+
m_ptr = nullptr;
|
314 |
+
return handle(tmp);
|
315 |
+
}
|
316 |
+
|
317 |
+
object &operator=(const object &other) {
|
318 |
+
other.inc_ref();
|
319 |
+
// Use temporary variable to ensure `*this` remains valid while
|
320 |
+
// `Py_XDECREF` executes, in case `*this` is accessible from Python.
|
321 |
+
handle temp(m_ptr);
|
322 |
+
m_ptr = other.m_ptr;
|
323 |
+
temp.dec_ref();
|
324 |
+
return *this;
|
325 |
+
}
|
326 |
+
|
327 |
+
object &operator=(object &&other) noexcept {
|
328 |
+
if (this != &other) {
|
329 |
+
handle temp(m_ptr);
|
330 |
+
m_ptr = other.m_ptr;
|
331 |
+
other.m_ptr = nullptr;
|
332 |
+
temp.dec_ref();
|
333 |
+
}
|
334 |
+
return *this;
|
335 |
+
}
|
336 |
+
|
337 |
+
// Calling cast() on an object lvalue just copies (via handle::cast)
|
338 |
+
template <typename T>
|
339 |
+
T cast() const &;
|
340 |
+
// Calling on an object rvalue does a move, if needed and/or possible
|
341 |
+
template <typename T>
|
342 |
+
T cast() &&;
|
343 |
+
|
344 |
+
protected:
|
345 |
+
// Tags for choosing constructors from raw PyObject *
|
346 |
+
struct borrowed_t {};
|
347 |
+
struct stolen_t {};
|
348 |
+
|
349 |
+
/// @cond BROKEN
|
350 |
+
template <typename T>
|
351 |
+
friend T reinterpret_borrow(handle);
|
352 |
+
template <typename T>
|
353 |
+
friend T reinterpret_steal(handle);
|
354 |
+
/// @endcond
|
355 |
+
|
356 |
+
public:
|
357 |
+
// Only accessible from derived classes and the reinterpret_* functions
|
358 |
+
object(handle h, borrowed_t) : handle(h) { inc_ref(); }
|
359 |
+
object(handle h, stolen_t) : handle(h) {}
|
360 |
+
};
|
361 |
+
|
362 |
+
/** \rst
|
363 |
+
Declare that a `handle` or ``PyObject *`` is a certain type and borrow the reference.
|
364 |
+
The target type ``T`` must be `object` or one of its derived classes. The function
|
365 |
+
doesn't do any conversions or checks. It's up to the user to make sure that the
|
366 |
+
target type is correct.
|
367 |
+
|
368 |
+
.. code-block:: cpp
|
369 |
+
|
370 |
+
PyObject *p = PyList_GetItem(obj, index);
|
371 |
+
py::object o = reinterpret_borrow<py::object>(p);
|
372 |
+
// or
|
373 |
+
py::tuple t = reinterpret_borrow<py::tuple>(p); // <-- `p` must be already be a `tuple`
|
374 |
+
\endrst */
|
375 |
+
template <typename T>
|
376 |
+
T reinterpret_borrow(handle h) {
|
377 |
+
return {h, object::borrowed_t{}};
|
378 |
+
}
|
379 |
+
|
380 |
+
/** \rst
|
381 |
+
Like `reinterpret_borrow`, but steals the reference.
|
382 |
+
|
383 |
+
.. code-block:: cpp
|
384 |
+
|
385 |
+
PyObject *p = PyObject_Str(obj);
|
386 |
+
py::str s = reinterpret_steal<py::str>(p); // <-- `p` must be already be a `str`
|
387 |
+
\endrst */
|
388 |
+
template <typename T>
|
389 |
+
T reinterpret_steal(handle h) {
|
390 |
+
return {h, object::stolen_t{}};
|
391 |
+
}
|
392 |
+
|
393 |
+
PYBIND11_NAMESPACE_BEGIN(detail)
|
394 |
+
|
395 |
+
// Equivalent to obj.__class__.__name__ (or obj.__name__ if obj is a class).
|
396 |
+
inline const char *obj_class_name(PyObject *obj) {
|
397 |
+
if (Py_TYPE(obj) == &PyType_Type) {
|
398 |
+
return reinterpret_cast<PyTypeObject *>(obj)->tp_name;
|
399 |
+
}
|
400 |
+
return Py_TYPE(obj)->tp_name;
|
401 |
+
}
|
402 |
+
|
403 |
+
std::string error_string();
|
404 |
+
|
405 |
+
struct error_fetch_and_normalize {
|
406 |
+
// Immediate normalization is long-established behavior (starting with
|
407 |
+
// https://github.com/pybind/pybind11/commit/135ba8deafb8bf64a15b24d1513899eb600e2011
|
408 |
+
// from Sep 2016) and safest. Normalization could be deferred, but this could mask
|
409 |
+
// errors elsewhere, the performance gain is very minor in typical situations
|
410 |
+
// (usually the dominant bottleneck is EH unwinding), and the implementation here
|
411 |
+
// would be more complex.
|
412 |
+
explicit error_fetch_and_normalize(const char *called) {
|
413 |
+
PyErr_Fetch(&m_type.ptr(), &m_value.ptr(), &m_trace.ptr());
|
414 |
+
if (!m_type) {
|
415 |
+
pybind11_fail("Internal error: " + std::string(called)
|
416 |
+
+ " called while "
|
417 |
+
"Python error indicator not set.");
|
418 |
+
}
|
419 |
+
const char *exc_type_name_orig = detail::obj_class_name(m_type.ptr());
|
420 |
+
if (exc_type_name_orig == nullptr) {
|
421 |
+
pybind11_fail("Internal error: " + std::string(called)
|
422 |
+
+ " failed to obtain the name "
|
423 |
+
"of the original active exception type.");
|
424 |
+
}
|
425 |
+
m_lazy_error_string = exc_type_name_orig;
|
426 |
+
// PyErr_NormalizeException() may change the exception type if there are cascading
|
427 |
+
// failures. This can potentially be extremely confusing.
|
428 |
+
PyErr_NormalizeException(&m_type.ptr(), &m_value.ptr(), &m_trace.ptr());
|
429 |
+
if (m_type.ptr() == nullptr) {
|
430 |
+
pybind11_fail("Internal error: " + std::string(called)
|
431 |
+
+ " failed to normalize the "
|
432 |
+
"active exception.");
|
433 |
+
}
|
434 |
+
const char *exc_type_name_norm = detail::obj_class_name(m_type.ptr());
|
435 |
+
if (exc_type_name_orig == nullptr) {
|
436 |
+
pybind11_fail("Internal error: " + std::string(called)
|
437 |
+
+ " failed to obtain the name "
|
438 |
+
"of the normalized active exception type.");
|
439 |
+
}
|
440 |
+
if (exc_type_name_norm != m_lazy_error_string) {
|
441 |
+
std::string msg = std::string(called)
|
442 |
+
+ ": MISMATCH of original and normalized "
|
443 |
+
"active exception types: ";
|
444 |
+
msg += "ORIGINAL ";
|
445 |
+
msg += m_lazy_error_string;
|
446 |
+
msg += " REPLACED BY ";
|
447 |
+
msg += exc_type_name_norm;
|
448 |
+
msg += ": " + format_value_and_trace();
|
449 |
+
pybind11_fail(msg);
|
450 |
+
}
|
451 |
+
}
|
452 |
+
|
453 |
+
error_fetch_and_normalize(const error_fetch_and_normalize &) = delete;
|
454 |
+
error_fetch_and_normalize(error_fetch_and_normalize &&) = delete;
|
455 |
+
|
456 |
+
std::string format_value_and_trace() const {
|
457 |
+
std::string result;
|
458 |
+
std::string message_error_string;
|
459 |
+
if (m_value) {
|
460 |
+
auto value_str = reinterpret_steal<object>(PyObject_Str(m_value.ptr()));
|
461 |
+
if (!value_str) {
|
462 |
+
message_error_string = detail::error_string();
|
463 |
+
result = "<MESSAGE UNAVAILABLE DUE TO ANOTHER EXCEPTION>";
|
464 |
+
} else {
|
465 |
+
result = value_str.cast<std::string>();
|
466 |
+
}
|
467 |
+
} else {
|
468 |
+
result = "<MESSAGE UNAVAILABLE>";
|
469 |
+
}
|
470 |
+
if (result.empty()) {
|
471 |
+
result = "<EMPTY MESSAGE>";
|
472 |
+
}
|
473 |
+
|
474 |
+
bool have_trace = false;
|
475 |
+
if (m_trace) {
|
476 |
+
#if !defined(PYPY_VERSION)
|
477 |
+
auto *tb = reinterpret_cast<PyTracebackObject *>(m_trace.ptr());
|
478 |
+
|
479 |
+
// Get the deepest trace possible.
|
480 |
+
while (tb->tb_next) {
|
481 |
+
tb = tb->tb_next;
|
482 |
+
}
|
483 |
+
|
484 |
+
PyFrameObject *frame = tb->tb_frame;
|
485 |
+
Py_XINCREF(frame);
|
486 |
+
result += "\n\nAt:\n";
|
487 |
+
while (frame) {
|
488 |
+
# if PY_VERSION_HEX >= 0x030900B1
|
489 |
+
PyCodeObject *f_code = PyFrame_GetCode(frame);
|
490 |
+
# else
|
491 |
+
PyCodeObject *f_code = frame->f_code;
|
492 |
+
Py_INCREF(f_code);
|
493 |
+
# endif
|
494 |
+
int lineno = PyFrame_GetLineNumber(frame);
|
495 |
+
result += " ";
|
496 |
+
result += handle(f_code->co_filename).cast<std::string>();
|
497 |
+
result += '(';
|
498 |
+
result += std::to_string(lineno);
|
499 |
+
result += "): ";
|
500 |
+
result += handle(f_code->co_name).cast<std::string>();
|
501 |
+
result += '\n';
|
502 |
+
Py_DECREF(f_code);
|
503 |
+
# if PY_VERSION_HEX >= 0x030900B1
|
504 |
+
auto *b_frame = PyFrame_GetBack(frame);
|
505 |
+
# else
|
506 |
+
auto *b_frame = frame->f_back;
|
507 |
+
Py_XINCREF(b_frame);
|
508 |
+
# endif
|
509 |
+
Py_DECREF(frame);
|
510 |
+
frame = b_frame;
|
511 |
+
}
|
512 |
+
|
513 |
+
have_trace = true;
|
514 |
+
#endif //! defined(PYPY_VERSION)
|
515 |
+
}
|
516 |
+
|
517 |
+
if (!message_error_string.empty()) {
|
518 |
+
if (!have_trace) {
|
519 |
+
result += '\n';
|
520 |
+
}
|
521 |
+
result += "\nMESSAGE UNAVAILABLE DUE TO EXCEPTION: " + message_error_string;
|
522 |
+
}
|
523 |
+
|
524 |
+
return result;
|
525 |
+
}
|
526 |
+
|
527 |
+
std::string const &error_string() const {
|
528 |
+
if (!m_lazy_error_string_completed) {
|
529 |
+
m_lazy_error_string += ": " + format_value_and_trace();
|
530 |
+
m_lazy_error_string_completed = true;
|
531 |
+
}
|
532 |
+
return m_lazy_error_string;
|
533 |
+
}
|
534 |
+
|
535 |
+
void restore() {
|
536 |
+
if (m_restore_called) {
|
537 |
+
pybind11_fail("Internal error: pybind11::detail::error_fetch_and_normalize::restore() "
|
538 |
+
"called a second time. ORIGINAL ERROR: "
|
539 |
+
+ error_string());
|
540 |
+
}
|
541 |
+
PyErr_Restore(m_type.inc_ref().ptr(), m_value.inc_ref().ptr(), m_trace.inc_ref().ptr());
|
542 |
+
m_restore_called = true;
|
543 |
+
}
|
544 |
+
|
545 |
+
bool matches(handle exc) const {
|
546 |
+
return (PyErr_GivenExceptionMatches(m_type.ptr(), exc.ptr()) != 0);
|
547 |
+
}
|
548 |
+
|
549 |
+
// Not protecting these for simplicity.
|
550 |
+
object m_type, m_value, m_trace;
|
551 |
+
|
552 |
+
private:
|
553 |
+
// Only protecting invariants.
|
554 |
+
mutable std::string m_lazy_error_string;
|
555 |
+
mutable bool m_lazy_error_string_completed = false;
|
556 |
+
mutable bool m_restore_called = false;
|
557 |
+
};
|
558 |
+
|
559 |
+
inline std::string error_string() {
|
560 |
+
return error_fetch_and_normalize("pybind11::detail::error_string").error_string();
|
561 |
+
}
|
562 |
+
|
563 |
+
PYBIND11_NAMESPACE_END(detail)
|
564 |
+
|
565 |
+
#if defined(_MSC_VER)
|
566 |
+
# pragma warning(push)
|
567 |
+
# pragma warning(disable : 4275 4251)
|
568 |
+
// warning C4275: An exported class was derived from a class that wasn't exported.
|
569 |
+
// Can be ignored when derived from a STL class.
|
570 |
+
#endif
|
571 |
+
/// Fetch and hold an error which was already set in Python. An instance of this is typically
|
572 |
+
/// thrown to propagate python-side errors back through C++ which can either be caught manually or
|
573 |
+
/// else falls back to the function dispatcher (which then raises the captured error back to
|
574 |
+
/// python).
|
575 |
+
class PYBIND11_EXPORT_EXCEPTION error_already_set : public std::exception {
|
576 |
+
public:
|
577 |
+
/// Fetches the current Python exception (using PyErr_Fetch()), which will clear the
|
578 |
+
/// current Python error indicator.
|
579 |
+
error_already_set()
|
580 |
+
: m_fetched_error{new detail::error_fetch_and_normalize("pybind11::error_already_set"),
|
581 |
+
m_fetched_error_deleter} {}
|
582 |
+
|
583 |
+
/// The what() result is built lazily on demand.
|
584 |
+
/// WARNING: This member function needs to acquire the Python GIL. This can lead to
|
585 |
+
/// crashes (undefined behavior) if the Python interpreter is finalizing.
|
586 |
+
const char *what() const noexcept override;
|
587 |
+
|
588 |
+
/// Restores the currently-held Python error (which will clear the Python error indicator first
|
589 |
+
/// if already set).
|
590 |
+
/// NOTE: This member function will always restore the normalized exception, which may or may
|
591 |
+
/// not be the original Python exception.
|
592 |
+
/// WARNING: The GIL must be held when this member function is called!
|
593 |
+
void restore() { m_fetched_error->restore(); }
|
594 |
+
|
595 |
+
/// If it is impossible to raise the currently-held error, such as in a destructor, we can
|
596 |
+
/// write it out using Python's unraisable hook (`sys.unraisablehook`). The error context
|
597 |
+
/// should be some object whose `repr()` helps identify the location of the error. Python
|
598 |
+
/// already knows the type and value of the error, so there is no need to repeat that.
|
599 |
+
void discard_as_unraisable(object err_context) {
|
600 |
+
restore();
|
601 |
+
PyErr_WriteUnraisable(err_context.ptr());
|
602 |
+
}
|
603 |
+
/// An alternate version of `discard_as_unraisable()`, where a string provides information on
|
604 |
+
/// the location of the error. For example, `__func__` could be helpful.
|
605 |
+
/// WARNING: The GIL must be held when this member function is called!
|
606 |
+
void discard_as_unraisable(const char *err_context) {
|
607 |
+
discard_as_unraisable(reinterpret_steal<object>(PYBIND11_FROM_STRING(err_context)));
|
608 |
+
}
|
609 |
+
|
610 |
+
// Does nothing; provided for backwards compatibility.
|
611 |
+
PYBIND11_DEPRECATED("Use of error_already_set.clear() is deprecated")
|
612 |
+
void clear() {}
|
613 |
+
|
614 |
+
/// Check if the currently trapped error type matches the given Python exception class (or a
|
615 |
+
/// subclass thereof). May also be passed a tuple to search for any exception class matches in
|
616 |
+
/// the given tuple.
|
617 |
+
bool matches(handle exc) const { return m_fetched_error->matches(exc); }
|
618 |
+
|
619 |
+
const object &type() const { return m_fetched_error->m_type; }
|
620 |
+
const object &value() const { return m_fetched_error->m_value; }
|
621 |
+
const object &trace() const { return m_fetched_error->m_trace; }
|
622 |
+
|
623 |
+
private:
|
624 |
+
std::shared_ptr<detail::error_fetch_and_normalize> m_fetched_error;
|
625 |
+
|
626 |
+
/// WARNING: This custom deleter needs to acquire the Python GIL. This can lead to
|
627 |
+
/// crashes (undefined behavior) if the Python interpreter is finalizing.
|
628 |
+
static void m_fetched_error_deleter(detail::error_fetch_and_normalize *raw_ptr);
|
629 |
+
};
|
630 |
+
#if defined(_MSC_VER)
|
631 |
+
# pragma warning(pop)
|
632 |
+
#endif
|
633 |
+
|
634 |
+
/// Replaces the current Python error indicator with the chosen error, performing a
|
635 |
+
/// 'raise from' to indicate that the chosen error was caused by the original error.
|
636 |
+
inline void raise_from(PyObject *type, const char *message) {
|
637 |
+
// Based on _PyErr_FormatVFromCause:
|
638 |
+
// https://github.com/python/cpython/blob/467ab194fc6189d9f7310c89937c51abeac56839/Python/errors.c#L405
|
639 |
+
// See https://github.com/pybind/pybind11/pull/2112 for details.
|
640 |
+
PyObject *exc = nullptr, *val = nullptr, *val2 = nullptr, *tb = nullptr;
|
641 |
+
|
642 |
+
assert(PyErr_Occurred());
|
643 |
+
PyErr_Fetch(&exc, &val, &tb);
|
644 |
+
PyErr_NormalizeException(&exc, &val, &tb);
|
645 |
+
if (tb != nullptr) {
|
646 |
+
PyException_SetTraceback(val, tb);
|
647 |
+
Py_DECREF(tb);
|
648 |
+
}
|
649 |
+
Py_DECREF(exc);
|
650 |
+
assert(!PyErr_Occurred());
|
651 |
+
|
652 |
+
PyErr_SetString(type, message);
|
653 |
+
|
654 |
+
PyErr_Fetch(&exc, &val2, &tb);
|
655 |
+
PyErr_NormalizeException(&exc, &val2, &tb);
|
656 |
+
Py_INCREF(val);
|
657 |
+
PyException_SetCause(val2, val);
|
658 |
+
PyException_SetContext(val2, val);
|
659 |
+
PyErr_Restore(exc, val2, tb);
|
660 |
+
}
|
661 |
+
|
662 |
+
/// Sets the current Python error indicator with the chosen error, performing a 'raise from'
|
663 |
+
/// from the error contained in error_already_set to indicate that the chosen error was
|
664 |
+
/// caused by the original error.
|
665 |
+
inline void raise_from(error_already_set &err, PyObject *type, const char *message) {
|
666 |
+
err.restore();
|
667 |
+
raise_from(type, message);
|
668 |
+
}
|
669 |
+
|
670 |
+
/** \defgroup python_builtins const_name
|
671 |
+
Unless stated otherwise, the following C++ functions behave the same
|
672 |
+
as their Python counterparts.
|
673 |
+
*/
|
674 |
+
|
675 |
+
/** \ingroup python_builtins
|
676 |
+
\rst
|
677 |
+
Return true if ``obj`` is an instance of ``T``. Type ``T`` must be a subclass of
|
678 |
+
`object` or a class which was exposed to Python as ``py::class_<T>``.
|
679 |
+
\endrst */
|
680 |
+
template <typename T, detail::enable_if_t<std::is_base_of<object, T>::value, int> = 0>
|
681 |
+
bool isinstance(handle obj) {
|
682 |
+
return T::check_(obj);
|
683 |
+
}
|
684 |
+
|
685 |
+
template <typename T, detail::enable_if_t<!std::is_base_of<object, T>::value, int> = 0>
|
686 |
+
bool isinstance(handle obj) {
|
687 |
+
return detail::isinstance_generic(obj, typeid(T));
|
688 |
+
}
|
689 |
+
|
690 |
+
template <>
|
691 |
+
inline bool isinstance<handle>(handle) = delete;
|
692 |
+
template <>
|
693 |
+
inline bool isinstance<object>(handle obj) {
|
694 |
+
return obj.ptr() != nullptr;
|
695 |
+
}
|
696 |
+
|
697 |
+
/// \ingroup python_builtins
|
698 |
+
/// Return true if ``obj`` is an instance of the ``type``.
|
699 |
+
inline bool isinstance(handle obj, handle type) {
|
700 |
+
const auto result = PyObject_IsInstance(obj.ptr(), type.ptr());
|
701 |
+
if (result == -1) {
|
702 |
+
throw error_already_set();
|
703 |
+
}
|
704 |
+
return result != 0;
|
705 |
+
}
|
706 |
+
|
707 |
+
/// \addtogroup python_builtins
|
708 |
+
/// @{
|
709 |
+
inline bool hasattr(handle obj, handle name) {
|
710 |
+
return PyObject_HasAttr(obj.ptr(), name.ptr()) == 1;
|
711 |
+
}
|
712 |
+
|
713 |
+
inline bool hasattr(handle obj, const char *name) {
|
714 |
+
return PyObject_HasAttrString(obj.ptr(), name) == 1;
|
715 |
+
}
|
716 |
+
|
717 |
+
inline void delattr(handle obj, handle name) {
|
718 |
+
if (PyObject_DelAttr(obj.ptr(), name.ptr()) != 0) {
|
719 |
+
throw error_already_set();
|
720 |
+
}
|
721 |
+
}
|
722 |
+
|
723 |
+
inline void delattr(handle obj, const char *name) {
|
724 |
+
if (PyObject_DelAttrString(obj.ptr(), name) != 0) {
|
725 |
+
throw error_already_set();
|
726 |
+
}
|
727 |
+
}
|
728 |
+
|
729 |
+
inline object getattr(handle obj, handle name) {
|
730 |
+
PyObject *result = PyObject_GetAttr(obj.ptr(), name.ptr());
|
731 |
+
if (!result) {
|
732 |
+
throw error_already_set();
|
733 |
+
}
|
734 |
+
return reinterpret_steal<object>(result);
|
735 |
+
}
|
736 |
+
|
737 |
+
inline object getattr(handle obj, const char *name) {
|
738 |
+
PyObject *result = PyObject_GetAttrString(obj.ptr(), name);
|
739 |
+
if (!result) {
|
740 |
+
throw error_already_set();
|
741 |
+
}
|
742 |
+
return reinterpret_steal<object>(result);
|
743 |
+
}
|
744 |
+
|
745 |
+
inline object getattr(handle obj, handle name, handle default_) {
|
746 |
+
if (PyObject *result = PyObject_GetAttr(obj.ptr(), name.ptr())) {
|
747 |
+
return reinterpret_steal<object>(result);
|
748 |
+
}
|
749 |
+
PyErr_Clear();
|
750 |
+
return reinterpret_borrow<object>(default_);
|
751 |
+
}
|
752 |
+
|
753 |
+
inline object getattr(handle obj, const char *name, handle default_) {
|
754 |
+
if (PyObject *result = PyObject_GetAttrString(obj.ptr(), name)) {
|
755 |
+
return reinterpret_steal<object>(result);
|
756 |
+
}
|
757 |
+
PyErr_Clear();
|
758 |
+
return reinterpret_borrow<object>(default_);
|
759 |
+
}
|
760 |
+
|
761 |
+
inline void setattr(handle obj, handle name, handle value) {
|
762 |
+
if (PyObject_SetAttr(obj.ptr(), name.ptr(), value.ptr()) != 0) {
|
763 |
+
throw error_already_set();
|
764 |
+
}
|
765 |
+
}
|
766 |
+
|
767 |
+
inline void setattr(handle obj, const char *name, handle value) {
|
768 |
+
if (PyObject_SetAttrString(obj.ptr(), name, value.ptr()) != 0) {
|
769 |
+
throw error_already_set();
|
770 |
+
}
|
771 |
+
}
|
772 |
+
|
773 |
+
inline ssize_t hash(handle obj) {
|
774 |
+
auto h = PyObject_Hash(obj.ptr());
|
775 |
+
if (h == -1) {
|
776 |
+
throw error_already_set();
|
777 |
+
}
|
778 |
+
return h;
|
779 |
+
}
|
780 |
+
|
781 |
+
/// @} python_builtins
|
782 |
+
|
783 |
+
PYBIND11_NAMESPACE_BEGIN(detail)
|
784 |
+
inline handle get_function(handle value) {
|
785 |
+
if (value) {
|
786 |
+
if (PyInstanceMethod_Check(value.ptr())) {
|
787 |
+
value = PyInstanceMethod_GET_FUNCTION(value.ptr());
|
788 |
+
} else if (PyMethod_Check(value.ptr())) {
|
789 |
+
value = PyMethod_GET_FUNCTION(value.ptr());
|
790 |
+
}
|
791 |
+
}
|
792 |
+
return value;
|
793 |
+
}
|
794 |
+
|
795 |
+
// Reimplementation of python's dict helper functions to ensure that exceptions
|
796 |
+
// aren't swallowed (see #2862)
|
797 |
+
|
798 |
+
// copied from cpython _PyDict_GetItemStringWithError
|
799 |
+
inline PyObject *dict_getitemstring(PyObject *v, const char *key) {
|
800 |
+
PyObject *kv = nullptr, *rv = nullptr;
|
801 |
+
kv = PyUnicode_FromString(key);
|
802 |
+
if (kv == nullptr) {
|
803 |
+
throw error_already_set();
|
804 |
+
}
|
805 |
+
|
806 |
+
rv = PyDict_GetItemWithError(v, kv);
|
807 |
+
Py_DECREF(kv);
|
808 |
+
if (rv == nullptr && PyErr_Occurred()) {
|
809 |
+
throw error_already_set();
|
810 |
+
}
|
811 |
+
return rv;
|
812 |
+
}
|
813 |
+
|
814 |
+
inline PyObject *dict_getitem(PyObject *v, PyObject *key) {
|
815 |
+
PyObject *rv = PyDict_GetItemWithError(v, key);
|
816 |
+
if (rv == nullptr && PyErr_Occurred()) {
|
817 |
+
throw error_already_set();
|
818 |
+
}
|
819 |
+
return rv;
|
820 |
+
}
|
821 |
+
|
822 |
+
// Helper aliases/functions to support implicit casting of values given to python
|
823 |
+
// accessors/methods. When given a pyobject, this simply returns the pyobject as-is; for other C++
|
824 |
+
// type, the value goes through pybind11::cast(obj) to convert it to an `object`.
|
825 |
+
template <typename T, enable_if_t<is_pyobject<T>::value, int> = 0>
|
826 |
+
auto object_or_cast(T &&o) -> decltype(std::forward<T>(o)) {
|
827 |
+
return std::forward<T>(o);
|
828 |
+
}
|
829 |
+
// The following casting version is implemented in cast.h:
|
830 |
+
template <typename T, enable_if_t<!is_pyobject<T>::value, int> = 0>
|
831 |
+
object object_or_cast(T &&o);
|
832 |
+
// Match a PyObject*, which we want to convert directly to handle via its converting constructor
|
833 |
+
inline handle object_or_cast(PyObject *ptr) { return ptr; }
|
834 |
+
|
835 |
+
#if defined(_MSC_VER) && _MSC_VER < 1920
|
836 |
+
# pragma warning(push)
|
837 |
+
# pragma warning(disable : 4522) // warning C4522: multiple assignment operators specified
|
838 |
+
#endif
|
839 |
+
template <typename Policy>
|
840 |
+
class accessor : public object_api<accessor<Policy>> {
|
841 |
+
using key_type = typename Policy::key_type;
|
842 |
+
|
843 |
+
public:
|
844 |
+
accessor(handle obj, key_type key) : obj(obj), key(std::move(key)) {}
|
845 |
+
accessor(const accessor &) = default;
|
846 |
+
accessor(accessor &&) noexcept = default;
|
847 |
+
|
848 |
+
// accessor overload required to override default assignment operator (templates are not
|
849 |
+
// allowed to replace default compiler-generated assignments).
|
850 |
+
void operator=(const accessor &a) && { std::move(*this).operator=(handle(a)); }
|
851 |
+
void operator=(const accessor &a) & { operator=(handle(a)); }
|
852 |
+
|
853 |
+
template <typename T>
|
854 |
+
void operator=(T &&value) && {
|
855 |
+
Policy::set(obj, key, object_or_cast(std::forward<T>(value)));
|
856 |
+
}
|
857 |
+
template <typename T>
|
858 |
+
void operator=(T &&value) & {
|
859 |
+
get_cache() = ensure_object(object_or_cast(std::forward<T>(value)));
|
860 |
+
}
|
861 |
+
|
862 |
+
template <typename T = Policy>
|
863 |
+
PYBIND11_DEPRECATED(
|
864 |
+
"Use of obj.attr(...) as bool is deprecated in favor of pybind11::hasattr(obj, ...)")
|
865 |
+
explicit
|
866 |
+
operator enable_if_t<std::is_same<T, accessor_policies::str_attr>::value
|
867 |
+
|| std::is_same<T, accessor_policies::obj_attr>::value,
|
868 |
+
bool>() const {
|
869 |
+
return hasattr(obj, key);
|
870 |
+
}
|
871 |
+
template <typename T = Policy>
|
872 |
+
PYBIND11_DEPRECATED("Use of obj[key] as bool is deprecated in favor of obj.contains(key)")
|
873 |
+
explicit
|
874 |
+
operator enable_if_t<std::is_same<T, accessor_policies::generic_item>::value, bool>() const {
|
875 |
+
return obj.contains(key);
|
876 |
+
}
|
877 |
+
|
878 |
+
// NOLINTNEXTLINE(google-explicit-constructor)
|
879 |
+
operator object() const { return get_cache(); }
|
880 |
+
PyObject *ptr() const { return get_cache().ptr(); }
|
881 |
+
template <typename T>
|
882 |
+
T cast() const {
|
883 |
+
return get_cache().template cast<T>();
|
884 |
+
}
|
885 |
+
|
886 |
+
private:
|
887 |
+
static object ensure_object(object &&o) { return std::move(o); }
|
888 |
+
static object ensure_object(handle h) { return reinterpret_borrow<object>(h); }
|
889 |
+
|
890 |
+
object &get_cache() const {
|
891 |
+
if (!cache) {
|
892 |
+
cache = Policy::get(obj, key);
|
893 |
+
}
|
894 |
+
return cache;
|
895 |
+
}
|
896 |
+
|
897 |
+
private:
|
898 |
+
handle obj;
|
899 |
+
key_type key;
|
900 |
+
mutable object cache;
|
901 |
+
};
|
902 |
+
#if defined(_MSC_VER) && _MSC_VER < 1920
|
903 |
+
# pragma warning(pop)
|
904 |
+
#endif
|
905 |
+
|
906 |
+
PYBIND11_NAMESPACE_BEGIN(accessor_policies)
|
907 |
+
struct obj_attr {
|
908 |
+
using key_type = object;
|
909 |
+
static object get(handle obj, handle key) { return getattr(obj, key); }
|
910 |
+
static void set(handle obj, handle key, handle val) { setattr(obj, key, val); }
|
911 |
+
};
|
912 |
+
|
913 |
+
struct str_attr {
|
914 |
+
using key_type = const char *;
|
915 |
+
static object get(handle obj, const char *key) { return getattr(obj, key); }
|
916 |
+
static void set(handle obj, const char *key, handle val) { setattr(obj, key, val); }
|
917 |
+
};
|
918 |
+
|
919 |
+
struct generic_item {
|
920 |
+
using key_type = object;
|
921 |
+
|
922 |
+
static object get(handle obj, handle key) {
|
923 |
+
PyObject *result = PyObject_GetItem(obj.ptr(), key.ptr());
|
924 |
+
if (!result) {
|
925 |
+
throw error_already_set();
|
926 |
+
}
|
927 |
+
return reinterpret_steal<object>(result);
|
928 |
+
}
|
929 |
+
|
930 |
+
static void set(handle obj, handle key, handle val) {
|
931 |
+
if (PyObject_SetItem(obj.ptr(), key.ptr(), val.ptr()) != 0) {
|
932 |
+
throw error_already_set();
|
933 |
+
}
|
934 |
+
}
|
935 |
+
};
|
936 |
+
|
937 |
+
struct sequence_item {
|
938 |
+
using key_type = size_t;
|
939 |
+
|
940 |
+
template <typename IdxType, detail::enable_if_t<std::is_integral<IdxType>::value, int> = 0>
|
941 |
+
static object get(handle obj, const IdxType &index) {
|
942 |
+
PyObject *result = PySequence_GetItem(obj.ptr(), ssize_t_cast(index));
|
943 |
+
if (!result) {
|
944 |
+
throw error_already_set();
|
945 |
+
}
|
946 |
+
return reinterpret_steal<object>(result);
|
947 |
+
}
|
948 |
+
|
949 |
+
template <typename IdxType, detail::enable_if_t<std::is_integral<IdxType>::value, int> = 0>
|
950 |
+
static void set(handle obj, const IdxType &index, handle val) {
|
951 |
+
// PySequence_SetItem does not steal a reference to 'val'
|
952 |
+
if (PySequence_SetItem(obj.ptr(), ssize_t_cast(index), val.ptr()) != 0) {
|
953 |
+
throw error_already_set();
|
954 |
+
}
|
955 |
+
}
|
956 |
+
};
|
957 |
+
|
958 |
+
struct list_item {
|
959 |
+
using key_type = size_t;
|
960 |
+
|
961 |
+
template <typename IdxType, detail::enable_if_t<std::is_integral<IdxType>::value, int> = 0>
|
962 |
+
static object get(handle obj, const IdxType &index) {
|
963 |
+
PyObject *result = PyList_GetItem(obj.ptr(), ssize_t_cast(index));
|
964 |
+
if (!result) {
|
965 |
+
throw error_already_set();
|
966 |
+
}
|
967 |
+
return reinterpret_borrow<object>(result);
|
968 |
+
}
|
969 |
+
|
970 |
+
template <typename IdxType, detail::enable_if_t<std::is_integral<IdxType>::value, int> = 0>
|
971 |
+
static void set(handle obj, const IdxType &index, handle val) {
|
972 |
+
// PyList_SetItem steals a reference to 'val'
|
973 |
+
if (PyList_SetItem(obj.ptr(), ssize_t_cast(index), val.inc_ref().ptr()) != 0) {
|
974 |
+
throw error_already_set();
|
975 |
+
}
|
976 |
+
}
|
977 |
+
};
|
978 |
+
|
979 |
+
struct tuple_item {
|
980 |
+
using key_type = size_t;
|
981 |
+
|
982 |
+
template <typename IdxType, detail::enable_if_t<std::is_integral<IdxType>::value, int> = 0>
|
983 |
+
static object get(handle obj, const IdxType &index) {
|
984 |
+
PyObject *result = PyTuple_GetItem(obj.ptr(), ssize_t_cast(index));
|
985 |
+
if (!result) {
|
986 |
+
throw error_already_set();
|
987 |
+
}
|
988 |
+
return reinterpret_borrow<object>(result);
|
989 |
+
}
|
990 |
+
|
991 |
+
template <typename IdxType, detail::enable_if_t<std::is_integral<IdxType>::value, int> = 0>
|
992 |
+
static void set(handle obj, const IdxType &index, handle val) {
|
993 |
+
// PyTuple_SetItem steals a reference to 'val'
|
994 |
+
if (PyTuple_SetItem(obj.ptr(), ssize_t_cast(index), val.inc_ref().ptr()) != 0) {
|
995 |
+
throw error_already_set();
|
996 |
+
}
|
997 |
+
}
|
998 |
+
};
|
999 |
+
PYBIND11_NAMESPACE_END(accessor_policies)
|
1000 |
+
|
1001 |
+
/// STL iterator template used for tuple, list, sequence and dict
|
1002 |
+
template <typename Policy>
|
1003 |
+
class generic_iterator : public Policy {
|
1004 |
+
using It = generic_iterator;
|
1005 |
+
|
1006 |
+
public:
|
1007 |
+
using difference_type = ssize_t;
|
1008 |
+
using iterator_category = typename Policy::iterator_category;
|
1009 |
+
using value_type = typename Policy::value_type;
|
1010 |
+
using reference = typename Policy::reference;
|
1011 |
+
using pointer = typename Policy::pointer;
|
1012 |
+
|
1013 |
+
generic_iterator() = default;
|
1014 |
+
generic_iterator(handle seq, ssize_t index) : Policy(seq, index) {}
|
1015 |
+
|
1016 |
+
// NOLINTNEXTLINE(readability-const-return-type) // PR #3263
|
1017 |
+
reference operator*() const { return Policy::dereference(); }
|
1018 |
+
// NOLINTNEXTLINE(readability-const-return-type) // PR #3263
|
1019 |
+
reference operator[](difference_type n) const { return *(*this + n); }
|
1020 |
+
pointer operator->() const { return **this; }
|
1021 |
+
|
1022 |
+
It &operator++() {
|
1023 |
+
Policy::increment();
|
1024 |
+
return *this;
|
1025 |
+
}
|
1026 |
+
It operator++(int) {
|
1027 |
+
auto copy = *this;
|
1028 |
+
Policy::increment();
|
1029 |
+
return copy;
|
1030 |
+
}
|
1031 |
+
It &operator--() {
|
1032 |
+
Policy::decrement();
|
1033 |
+
return *this;
|
1034 |
+
}
|
1035 |
+
It operator--(int) {
|
1036 |
+
auto copy = *this;
|
1037 |
+
Policy::decrement();
|
1038 |
+
return copy;
|
1039 |
+
}
|
1040 |
+
It &operator+=(difference_type n) {
|
1041 |
+
Policy::advance(n);
|
1042 |
+
return *this;
|
1043 |
+
}
|
1044 |
+
It &operator-=(difference_type n) {
|
1045 |
+
Policy::advance(-n);
|
1046 |
+
return *this;
|
1047 |
+
}
|
1048 |
+
|
1049 |
+
friend It operator+(const It &a, difference_type n) {
|
1050 |
+
auto copy = a;
|
1051 |
+
return copy += n;
|
1052 |
+
}
|
1053 |
+
friend It operator+(difference_type n, const It &b) { return b + n; }
|
1054 |
+
friend It operator-(const It &a, difference_type n) {
|
1055 |
+
auto copy = a;
|
1056 |
+
return copy -= n;
|
1057 |
+
}
|
1058 |
+
friend difference_type operator-(const It &a, const It &b) { return a.distance_to(b); }
|
1059 |
+
|
1060 |
+
friend bool operator==(const It &a, const It &b) { return a.equal(b); }
|
1061 |
+
friend bool operator!=(const It &a, const It &b) { return !(a == b); }
|
1062 |
+
friend bool operator<(const It &a, const It &b) { return b - a > 0; }
|
1063 |
+
friend bool operator>(const It &a, const It &b) { return b < a; }
|
1064 |
+
friend bool operator>=(const It &a, const It &b) { return !(a < b); }
|
1065 |
+
friend bool operator<=(const It &a, const It &b) { return !(a > b); }
|
1066 |
+
};
|
1067 |
+
|
1068 |
+
PYBIND11_NAMESPACE_BEGIN(iterator_policies)
|
1069 |
+
/// Quick proxy class needed to implement ``operator->`` for iterators which can't return pointers
|
1070 |
+
template <typename T>
|
1071 |
+
struct arrow_proxy {
|
1072 |
+
T value;
|
1073 |
+
|
1074 |
+
// NOLINTNEXTLINE(google-explicit-constructor)
|
1075 |
+
arrow_proxy(T &&value) noexcept : value(std::move(value)) {}
|
1076 |
+
T *operator->() const { return &value; }
|
1077 |
+
};
|
1078 |
+
|
1079 |
+
/// Lightweight iterator policy using just a simple pointer: see ``PySequence_Fast_ITEMS``
|
1080 |
+
class sequence_fast_readonly {
|
1081 |
+
protected:
|
1082 |
+
using iterator_category = std::random_access_iterator_tag;
|
1083 |
+
using value_type = handle;
|
1084 |
+
using reference = const handle; // PR #3263
|
1085 |
+
using pointer = arrow_proxy<const handle>;
|
1086 |
+
|
1087 |
+
sequence_fast_readonly(handle obj, ssize_t n) : ptr(PySequence_Fast_ITEMS(obj.ptr()) + n) {}
|
1088 |
+
|
1089 |
+
// NOLINTNEXTLINE(readability-const-return-type) // PR #3263
|
1090 |
+
reference dereference() const { return *ptr; }
|
1091 |
+
void increment() { ++ptr; }
|
1092 |
+
void decrement() { --ptr; }
|
1093 |
+
void advance(ssize_t n) { ptr += n; }
|
1094 |
+
bool equal(const sequence_fast_readonly &b) const { return ptr == b.ptr; }
|
1095 |
+
ssize_t distance_to(const sequence_fast_readonly &b) const { return ptr - b.ptr; }
|
1096 |
+
|
1097 |
+
private:
|
1098 |
+
PyObject **ptr;
|
1099 |
+
};
|
1100 |
+
|
1101 |
+
/// Full read and write access using the sequence protocol: see ``detail::sequence_accessor``
|
1102 |
+
class sequence_slow_readwrite {
|
1103 |
+
protected:
|
1104 |
+
using iterator_category = std::random_access_iterator_tag;
|
1105 |
+
using value_type = object;
|
1106 |
+
using reference = sequence_accessor;
|
1107 |
+
using pointer = arrow_proxy<const sequence_accessor>;
|
1108 |
+
|
1109 |
+
sequence_slow_readwrite(handle obj, ssize_t index) : obj(obj), index(index) {}
|
1110 |
+
|
1111 |
+
reference dereference() const { return {obj, static_cast<size_t>(index)}; }
|
1112 |
+
void increment() { ++index; }
|
1113 |
+
void decrement() { --index; }
|
1114 |
+
void advance(ssize_t n) { index += n; }
|
1115 |
+
bool equal(const sequence_slow_readwrite &b) const { return index == b.index; }
|
1116 |
+
ssize_t distance_to(const sequence_slow_readwrite &b) const { return index - b.index; }
|
1117 |
+
|
1118 |
+
private:
|
1119 |
+
handle obj;
|
1120 |
+
ssize_t index;
|
1121 |
+
};
|
1122 |
+
|
1123 |
+
/// Python's dictionary protocol permits this to be a forward iterator
|
1124 |
+
class dict_readonly {
|
1125 |
+
protected:
|
1126 |
+
using iterator_category = std::forward_iterator_tag;
|
1127 |
+
using value_type = std::pair<handle, handle>;
|
1128 |
+
using reference = const value_type; // PR #3263
|
1129 |
+
using pointer = arrow_proxy<const value_type>;
|
1130 |
+
|
1131 |
+
dict_readonly() = default;
|
1132 |
+
dict_readonly(handle obj, ssize_t pos) : obj(obj), pos(pos) { increment(); }
|
1133 |
+
|
1134 |
+
// NOLINTNEXTLINE(readability-const-return-type) // PR #3263
|
1135 |
+
reference dereference() const { return {key, value}; }
|
1136 |
+
void increment() {
|
1137 |
+
if (PyDict_Next(obj.ptr(), &pos, &key, &value) == 0) {
|
1138 |
+
pos = -1;
|
1139 |
+
}
|
1140 |
+
}
|
1141 |
+
bool equal(const dict_readonly &b) const { return pos == b.pos; }
|
1142 |
+
|
1143 |
+
private:
|
1144 |
+
handle obj;
|
1145 |
+
PyObject *key = nullptr, *value = nullptr;
|
1146 |
+
ssize_t pos = -1;
|
1147 |
+
};
|
1148 |
+
PYBIND11_NAMESPACE_END(iterator_policies)
|
1149 |
+
|
1150 |
+
#if !defined(PYPY_VERSION)
|
1151 |
+
using tuple_iterator = generic_iterator<iterator_policies::sequence_fast_readonly>;
|
1152 |
+
using list_iterator = generic_iterator<iterator_policies::sequence_fast_readonly>;
|
1153 |
+
#else
|
1154 |
+
using tuple_iterator = generic_iterator<iterator_policies::sequence_slow_readwrite>;
|
1155 |
+
using list_iterator = generic_iterator<iterator_policies::sequence_slow_readwrite>;
|
1156 |
+
#endif
|
1157 |
+
|
1158 |
+
using sequence_iterator = generic_iterator<iterator_policies::sequence_slow_readwrite>;
|
1159 |
+
using dict_iterator = generic_iterator<iterator_policies::dict_readonly>;
|
1160 |
+
|
1161 |
+
inline bool PyIterable_Check(PyObject *obj) {
|
1162 |
+
PyObject *iter = PyObject_GetIter(obj);
|
1163 |
+
if (iter) {
|
1164 |
+
Py_DECREF(iter);
|
1165 |
+
return true;
|
1166 |
+
}
|
1167 |
+
PyErr_Clear();
|
1168 |
+
return false;
|
1169 |
+
}
|
1170 |
+
|
1171 |
+
inline bool PyNone_Check(PyObject *o) { return o == Py_None; }
|
1172 |
+
inline bool PyEllipsis_Check(PyObject *o) { return o == Py_Ellipsis; }
|
1173 |
+
|
1174 |
+
#ifdef PYBIND11_STR_LEGACY_PERMISSIVE
|
1175 |
+
inline bool PyUnicode_Check_Permissive(PyObject *o) {
|
1176 |
+
return PyUnicode_Check(o) || PYBIND11_BYTES_CHECK(o);
|
1177 |
+
}
|
1178 |
+
# define PYBIND11_STR_CHECK_FUN detail::PyUnicode_Check_Permissive
|
1179 |
+
#else
|
1180 |
+
# define PYBIND11_STR_CHECK_FUN PyUnicode_Check
|
1181 |
+
#endif
|
1182 |
+
|
1183 |
+
inline bool PyStaticMethod_Check(PyObject *o) { return o->ob_type == &PyStaticMethod_Type; }
|
1184 |
+
|
1185 |
+
class kwargs_proxy : public handle {
|
1186 |
+
public:
|
1187 |
+
explicit kwargs_proxy(handle h) : handle(h) {}
|
1188 |
+
};
|
1189 |
+
|
1190 |
+
class args_proxy : public handle {
|
1191 |
+
public:
|
1192 |
+
explicit args_proxy(handle h) : handle(h) {}
|
1193 |
+
kwargs_proxy operator*() const { return kwargs_proxy(*this); }
|
1194 |
+
};
|
1195 |
+
|
1196 |
+
/// Python argument categories (using PEP 448 terms)
|
1197 |
+
template <typename T>
|
1198 |
+
using is_keyword = std::is_base_of<arg, T>;
|
1199 |
+
template <typename T>
|
1200 |
+
using is_s_unpacking = std::is_same<args_proxy, T>; // * unpacking
|
1201 |
+
template <typename T>
|
1202 |
+
using is_ds_unpacking = std::is_same<kwargs_proxy, T>; // ** unpacking
|
1203 |
+
template <typename T>
|
1204 |
+
using is_positional = satisfies_none_of<T, is_keyword, is_s_unpacking, is_ds_unpacking>;
|
1205 |
+
template <typename T>
|
1206 |
+
using is_keyword_or_ds = satisfies_any_of<T, is_keyword, is_ds_unpacking>;
|
1207 |
+
|
1208 |
+
// Call argument collector forward declarations
|
1209 |
+
template <return_value_policy policy = return_value_policy::automatic_reference>
|
1210 |
+
class simple_collector;
|
1211 |
+
template <return_value_policy policy = return_value_policy::automatic_reference>
|
1212 |
+
class unpacking_collector;
|
1213 |
+
|
1214 |
+
PYBIND11_NAMESPACE_END(detail)
|
1215 |
+
|
1216 |
+
// TODO: After the deprecated constructors are removed, this macro can be simplified by
|
1217 |
+
// inheriting ctors: `using Parent::Parent`. It's not an option right now because
|
1218 |
+
// the `using` statement triggers the parent deprecation warning even if the ctor
|
1219 |
+
// isn't even used.
|
1220 |
+
#define PYBIND11_OBJECT_COMMON(Name, Parent, CheckFun) \
|
1221 |
+
public: \
|
1222 |
+
PYBIND11_DEPRECATED("Use reinterpret_borrow<" #Name ">() or reinterpret_steal<" #Name ">()") \
|
1223 |
+
Name(handle h, bool is_borrowed) \
|
1224 |
+
: Parent(is_borrowed ? Parent(h, borrowed_t{}) : Parent(h, stolen_t{})) {} \
|
1225 |
+
Name(handle h, borrowed_t) : Parent(h, borrowed_t{}) {} \
|
1226 |
+
Name(handle h, stolen_t) : Parent(h, stolen_t{}) {} \
|
1227 |
+
PYBIND11_DEPRECATED("Use py::isinstance<py::python_type>(obj) instead") \
|
1228 |
+
bool check() const { return m_ptr != nullptr && (CheckFun(m_ptr) != 0); } \
|
1229 |
+
static bool check_(handle h) { return h.ptr() != nullptr && CheckFun(h.ptr()); } \
|
1230 |
+
template <typename Policy_> /* NOLINTNEXTLINE(google-explicit-constructor) */ \
|
1231 |
+
Name(const ::pybind11::detail::accessor<Policy_> &a) : Name(object(a)) {}
|
1232 |
+
|
1233 |
+
#define PYBIND11_OBJECT_CVT(Name, Parent, CheckFun, ConvertFun) \
|
1234 |
+
PYBIND11_OBJECT_COMMON(Name, Parent, CheckFun) \
|
1235 |
+
/* This is deliberately not 'explicit' to allow implicit conversion from object: */ \
|
1236 |
+
/* NOLINTNEXTLINE(google-explicit-constructor) */ \
|
1237 |
+
Name(const object &o) \
|
1238 |
+
: Parent(check_(o) ? o.inc_ref().ptr() : ConvertFun(o.ptr()), stolen_t{}) { \
|
1239 |
+
if (!m_ptr) \
|
1240 |
+
throw ::pybind11::error_already_set(); \
|
1241 |
+
} \
|
1242 |
+
/* NOLINTNEXTLINE(google-explicit-constructor) */ \
|
1243 |
+
Name(object &&o) : Parent(check_(o) ? o.release().ptr() : ConvertFun(o.ptr()), stolen_t{}) { \
|
1244 |
+
if (!m_ptr) \
|
1245 |
+
throw ::pybind11::error_already_set(); \
|
1246 |
+
}
|
1247 |
+
|
1248 |
+
#define PYBIND11_OBJECT_CVT_DEFAULT(Name, Parent, CheckFun, ConvertFun) \
|
1249 |
+
PYBIND11_OBJECT_CVT(Name, Parent, CheckFun, ConvertFun) \
|
1250 |
+
Name() : Parent() {}
|
1251 |
+
|
1252 |
+
#define PYBIND11_OBJECT_CHECK_FAILED(Name, o_ptr) \
|
1253 |
+
::pybind11::type_error("Object of type '" \
|
1254 |
+
+ ::pybind11::detail::get_fully_qualified_tp_name(Py_TYPE(o_ptr)) \
|
1255 |
+
+ "' is not an instance of '" #Name "'")
|
1256 |
+
|
1257 |
+
#define PYBIND11_OBJECT(Name, Parent, CheckFun) \
|
1258 |
+
PYBIND11_OBJECT_COMMON(Name, Parent, CheckFun) \
|
1259 |
+
/* This is deliberately not 'explicit' to allow implicit conversion from object: */ \
|
1260 |
+
/* NOLINTNEXTLINE(google-explicit-constructor) */ \
|
1261 |
+
Name(const object &o) : Parent(o) { \
|
1262 |
+
if (m_ptr && !check_(m_ptr)) \
|
1263 |
+
throw PYBIND11_OBJECT_CHECK_FAILED(Name, m_ptr); \
|
1264 |
+
} \
|
1265 |
+
/* NOLINTNEXTLINE(google-explicit-constructor) */ \
|
1266 |
+
Name(object &&o) : Parent(std::move(o)) { \
|
1267 |
+
if (m_ptr && !check_(m_ptr)) \
|
1268 |
+
throw PYBIND11_OBJECT_CHECK_FAILED(Name, m_ptr); \
|
1269 |
+
}
|
1270 |
+
|
1271 |
+
#define PYBIND11_OBJECT_DEFAULT(Name, Parent, CheckFun) \
|
1272 |
+
PYBIND11_OBJECT(Name, Parent, CheckFun) \
|
1273 |
+
Name() : Parent() {}
|
1274 |
+
|
1275 |
+
/// \addtogroup pytypes
|
1276 |
+
/// @{
|
1277 |
+
|
1278 |
+
/** \rst
|
1279 |
+
Wraps a Python iterator so that it can also be used as a C++ input iterator
|
1280 |
+
|
1281 |
+
Caveat: copying an iterator does not (and cannot) clone the internal
|
1282 |
+
state of the Python iterable. This also applies to the post-increment
|
1283 |
+
operator. This iterator should only be used to retrieve the current
|
1284 |
+
value using ``operator*()``.
|
1285 |
+
\endrst */
|
1286 |
+
class iterator : public object {
|
1287 |
+
public:
|
1288 |
+
using iterator_category = std::input_iterator_tag;
|
1289 |
+
using difference_type = ssize_t;
|
1290 |
+
using value_type = handle;
|
1291 |
+
using reference = const handle; // PR #3263
|
1292 |
+
using pointer = const handle *;
|
1293 |
+
|
1294 |
+
PYBIND11_OBJECT_DEFAULT(iterator, object, PyIter_Check)
|
1295 |
+
|
1296 |
+
iterator &operator++() {
|
1297 |
+
advance();
|
1298 |
+
return *this;
|
1299 |
+
}
|
1300 |
+
|
1301 |
+
iterator operator++(int) {
|
1302 |
+
auto rv = *this;
|
1303 |
+
advance();
|
1304 |
+
return rv;
|
1305 |
+
}
|
1306 |
+
|
1307 |
+
// NOLINTNEXTLINE(readability-const-return-type) // PR #3263
|
1308 |
+
reference operator*() const {
|
1309 |
+
if (m_ptr && !value.ptr()) {
|
1310 |
+
auto &self = const_cast<iterator &>(*this);
|
1311 |
+
self.advance();
|
1312 |
+
}
|
1313 |
+
return value;
|
1314 |
+
}
|
1315 |
+
|
1316 |
+
pointer operator->() const {
|
1317 |
+
operator*();
|
1318 |
+
return &value;
|
1319 |
+
}
|
1320 |
+
|
1321 |
+
/** \rst
|
1322 |
+
The value which marks the end of the iteration. ``it == iterator::sentinel()``
|
1323 |
+
is equivalent to catching ``StopIteration`` in Python.
|
1324 |
+
|
1325 |
+
.. code-block:: cpp
|
1326 |
+
|
1327 |
+
void foo(py::iterator it) {
|
1328 |
+
while (it != py::iterator::sentinel()) {
|
1329 |
+
// use `*it`
|
1330 |
+
++it;
|
1331 |
+
}
|
1332 |
+
}
|
1333 |
+
\endrst */
|
1334 |
+
static iterator sentinel() { return {}; }
|
1335 |
+
|
1336 |
+
friend bool operator==(const iterator &a, const iterator &b) { return a->ptr() == b->ptr(); }
|
1337 |
+
friend bool operator!=(const iterator &a, const iterator &b) { return a->ptr() != b->ptr(); }
|
1338 |
+
|
1339 |
+
private:
|
1340 |
+
void advance() {
|
1341 |
+
value = reinterpret_steal<object>(PyIter_Next(m_ptr));
|
1342 |
+
if (PyErr_Occurred()) {
|
1343 |
+
throw error_already_set();
|
1344 |
+
}
|
1345 |
+
}
|
1346 |
+
|
1347 |
+
private:
|
1348 |
+
object value = {};
|
1349 |
+
};
|
1350 |
+
|
1351 |
+
class type : public object {
|
1352 |
+
public:
|
1353 |
+
PYBIND11_OBJECT(type, object, PyType_Check)
|
1354 |
+
|
1355 |
+
/// Return a type handle from a handle or an object
|
1356 |
+
static handle handle_of(handle h) { return handle((PyObject *) Py_TYPE(h.ptr())); }
|
1357 |
+
|
1358 |
+
/// Return a type object from a handle or an object
|
1359 |
+
static type of(handle h) { return type(type::handle_of(h), borrowed_t{}); }
|
1360 |
+
|
1361 |
+
// Defined in pybind11/cast.h
|
1362 |
+
/// Convert C++ type to handle if previously registered. Does not convert
|
1363 |
+
/// standard types, like int, float. etc. yet.
|
1364 |
+
/// See https://github.com/pybind/pybind11/issues/2486
|
1365 |
+
template <typename T>
|
1366 |
+
static handle handle_of();
|
1367 |
+
|
1368 |
+
/// Convert C++ type to type if previously registered. Does not convert
|
1369 |
+
/// standard types, like int, float. etc. yet.
|
1370 |
+
/// See https://github.com/pybind/pybind11/issues/2486
|
1371 |
+
template <typename T>
|
1372 |
+
static type of() {
|
1373 |
+
return type(type::handle_of<T>(), borrowed_t{});
|
1374 |
+
}
|
1375 |
+
};
|
1376 |
+
|
1377 |
+
class iterable : public object {
|
1378 |
+
public:
|
1379 |
+
PYBIND11_OBJECT_DEFAULT(iterable, object, detail::PyIterable_Check)
|
1380 |
+
};
|
1381 |
+
|
1382 |
+
class bytes;
|
1383 |
+
|
1384 |
+
class str : public object {
|
1385 |
+
public:
|
1386 |
+
PYBIND11_OBJECT_CVT(str, object, PYBIND11_STR_CHECK_FUN, raw_str)
|
1387 |
+
|
1388 |
+
template <typename SzType, detail::enable_if_t<std::is_integral<SzType>::value, int> = 0>
|
1389 |
+
str(const char *c, const SzType &n)
|
1390 |
+
: object(PyUnicode_FromStringAndSize(c, ssize_t_cast(n)), stolen_t{}) {
|
1391 |
+
if (!m_ptr) {
|
1392 |
+
pybind11_fail("Could not allocate string object!");
|
1393 |
+
}
|
1394 |
+
}
|
1395 |
+
|
1396 |
+
// 'explicit' is explicitly omitted from the following constructors to allow implicit
|
1397 |
+
// conversion to py::str from C++ string-like objects
|
1398 |
+
// NOLINTNEXTLINE(google-explicit-constructor)
|
1399 |
+
str(const char *c = "") : object(PyUnicode_FromString(c), stolen_t{}) {
|
1400 |
+
if (!m_ptr) {
|
1401 |
+
pybind11_fail("Could not allocate string object!");
|
1402 |
+
}
|
1403 |
+
}
|
1404 |
+
|
1405 |
+
// NOLINTNEXTLINE(google-explicit-constructor)
|
1406 |
+
str(const std::string &s) : str(s.data(), s.size()) {}
|
1407 |
+
|
1408 |
+
#ifdef PYBIND11_HAS_STRING_VIEW
|
1409 |
+
// enable_if is needed to avoid "ambiguous conversion" errors (see PR #3521).
|
1410 |
+
template <typename T, detail::enable_if_t<std::is_same<T, std::string_view>::value, int> = 0>
|
1411 |
+
// NOLINTNEXTLINE(google-explicit-constructor)
|
1412 |
+
str(T s) : str(s.data(), s.size()) {}
|
1413 |
+
|
1414 |
+
# ifdef PYBIND11_HAS_U8STRING
|
1415 |
+
// reinterpret_cast here is safe (C++20 guarantees char8_t has the same size/alignment as char)
|
1416 |
+
// NOLINTNEXTLINE(google-explicit-constructor)
|
1417 |
+
str(std::u8string_view s) : str(reinterpret_cast<const char *>(s.data()), s.size()) {}
|
1418 |
+
# endif
|
1419 |
+
|
1420 |
+
#endif
|
1421 |
+
|
1422 |
+
explicit str(const bytes &b);
|
1423 |
+
|
1424 |
+
/** \rst
|
1425 |
+
Return a string representation of the object. This is analogous to
|
1426 |
+
the ``str()`` function in Python.
|
1427 |
+
\endrst */
|
1428 |
+
explicit str(handle h) : object(raw_str(h.ptr()), stolen_t{}) {
|
1429 |
+
if (!m_ptr) {
|
1430 |
+
throw error_already_set();
|
1431 |
+
}
|
1432 |
+
}
|
1433 |
+
|
1434 |
+
// NOLINTNEXTLINE(google-explicit-constructor)
|
1435 |
+
operator std::string() const {
|
1436 |
+
object temp = *this;
|
1437 |
+
if (PyUnicode_Check(m_ptr)) {
|
1438 |
+
temp = reinterpret_steal<object>(PyUnicode_AsUTF8String(m_ptr));
|
1439 |
+
if (!temp) {
|
1440 |
+
throw error_already_set();
|
1441 |
+
}
|
1442 |
+
}
|
1443 |
+
char *buffer = nullptr;
|
1444 |
+
ssize_t length = 0;
|
1445 |
+
if (PyBytes_AsStringAndSize(temp.ptr(), &buffer, &length) != 0) {
|
1446 |
+
throw error_already_set();
|
1447 |
+
}
|
1448 |
+
return std::string(buffer, (size_t) length);
|
1449 |
+
}
|
1450 |
+
|
1451 |
+
template <typename... Args>
|
1452 |
+
str format(Args &&...args) const {
|
1453 |
+
return attr("format")(std::forward<Args>(args)...);
|
1454 |
+
}
|
1455 |
+
|
1456 |
+
private:
|
1457 |
+
/// Return string representation -- always returns a new reference, even if already a str
|
1458 |
+
static PyObject *raw_str(PyObject *op) {
|
1459 |
+
PyObject *str_value = PyObject_Str(op);
|
1460 |
+
return str_value;
|
1461 |
+
}
|
1462 |
+
};
|
1463 |
+
/// @} pytypes
|
1464 |
+
|
1465 |
+
inline namespace literals {
|
1466 |
+
/** \rst
|
1467 |
+
String literal version of `str`
|
1468 |
+
\endrst */
|
1469 |
+
inline str operator"" _s(const char *s, size_t size) { return {s, size}; }
|
1470 |
+
} // namespace literals
|
1471 |
+
|
1472 |
+
/// \addtogroup pytypes
|
1473 |
+
/// @{
|
1474 |
+
class bytes : public object {
|
1475 |
+
public:
|
1476 |
+
PYBIND11_OBJECT(bytes, object, PYBIND11_BYTES_CHECK)
|
1477 |
+
|
1478 |
+
// Allow implicit conversion:
|
1479 |
+
// NOLINTNEXTLINE(google-explicit-constructor)
|
1480 |
+
bytes(const char *c = "") : object(PYBIND11_BYTES_FROM_STRING(c), stolen_t{}) {
|
1481 |
+
if (!m_ptr) {
|
1482 |
+
pybind11_fail("Could not allocate bytes object!");
|
1483 |
+
}
|
1484 |
+
}
|
1485 |
+
|
1486 |
+
template <typename SzType, detail::enable_if_t<std::is_integral<SzType>::value, int> = 0>
|
1487 |
+
bytes(const char *c, const SzType &n)
|
1488 |
+
: object(PYBIND11_BYTES_FROM_STRING_AND_SIZE(c, ssize_t_cast(n)), stolen_t{}) {
|
1489 |
+
if (!m_ptr) {
|
1490 |
+
pybind11_fail("Could not allocate bytes object!");
|
1491 |
+
}
|
1492 |
+
}
|
1493 |
+
|
1494 |
+
// Allow implicit conversion:
|
1495 |
+
// NOLINTNEXTLINE(google-explicit-constructor)
|
1496 |
+
bytes(const std::string &s) : bytes(s.data(), s.size()) {}
|
1497 |
+
|
1498 |
+
explicit bytes(const pybind11::str &s);
|
1499 |
+
|
1500 |
+
// NOLINTNEXTLINE(google-explicit-constructor)
|
1501 |
+
operator std::string() const { return string_op<std::string>(); }
|
1502 |
+
|
1503 |
+
#ifdef PYBIND11_HAS_STRING_VIEW
|
1504 |
+
// enable_if is needed to avoid "ambiguous conversion" errors (see PR #3521).
|
1505 |
+
template <typename T, detail::enable_if_t<std::is_same<T, std::string_view>::value, int> = 0>
|
1506 |
+
// NOLINTNEXTLINE(google-explicit-constructor)
|
1507 |
+
bytes(T s) : bytes(s.data(), s.size()) {}
|
1508 |
+
|
1509 |
+
// Obtain a string view that views the current `bytes` buffer value. Note that this is only
|
1510 |
+
// valid so long as the `bytes` instance remains alive and so generally should not outlive the
|
1511 |
+
// lifetime of the `bytes` instance.
|
1512 |
+
// NOLINTNEXTLINE(google-explicit-constructor)
|
1513 |
+
operator std::string_view() const { return string_op<std::string_view>(); }
|
1514 |
+
#endif
|
1515 |
+
private:
|
1516 |
+
template <typename T>
|
1517 |
+
T string_op() const {
|
1518 |
+
char *buffer = nullptr;
|
1519 |
+
ssize_t length = 0;
|
1520 |
+
if (PyBytes_AsStringAndSize(m_ptr, &buffer, &length) != 0) {
|
1521 |
+
throw error_already_set();
|
1522 |
+
}
|
1523 |
+
return {buffer, static_cast<size_t>(length)};
|
1524 |
+
}
|
1525 |
+
};
|
1526 |
+
// Note: breathe >= 4.17.0 will fail to build docs if the below two constructors
|
1527 |
+
// are included in the doxygen group; close here and reopen after as a workaround
|
1528 |
+
/// @} pytypes
|
1529 |
+
|
1530 |
+
inline bytes::bytes(const pybind11::str &s) {
|
1531 |
+
object temp = s;
|
1532 |
+
if (PyUnicode_Check(s.ptr())) {
|
1533 |
+
temp = reinterpret_steal<object>(PyUnicode_AsUTF8String(s.ptr()));
|
1534 |
+
if (!temp) {
|
1535 |
+
throw error_already_set();
|
1536 |
+
}
|
1537 |
+
}
|
1538 |
+
char *buffer = nullptr;
|
1539 |
+
ssize_t length = 0;
|
1540 |
+
if (PyBytes_AsStringAndSize(temp.ptr(), &buffer, &length) != 0) {
|
1541 |
+
throw error_already_set();
|
1542 |
+
}
|
1543 |
+
auto obj = reinterpret_steal<object>(PYBIND11_BYTES_FROM_STRING_AND_SIZE(buffer, length));
|
1544 |
+
if (!obj) {
|
1545 |
+
pybind11_fail("Could not allocate bytes object!");
|
1546 |
+
}
|
1547 |
+
m_ptr = obj.release().ptr();
|
1548 |
+
}
|
1549 |
+
|
1550 |
+
inline str::str(const bytes &b) {
|
1551 |
+
char *buffer = nullptr;
|
1552 |
+
ssize_t length = 0;
|
1553 |
+
if (PyBytes_AsStringAndSize(b.ptr(), &buffer, &length) != 0) {
|
1554 |
+
throw error_already_set();
|
1555 |
+
}
|
1556 |
+
auto obj = reinterpret_steal<object>(PyUnicode_FromStringAndSize(buffer, length));
|
1557 |
+
if (!obj) {
|
1558 |
+
pybind11_fail("Could not allocate string object!");
|
1559 |
+
}
|
1560 |
+
m_ptr = obj.release().ptr();
|
1561 |
+
}
|
1562 |
+
|
1563 |
+
/// \addtogroup pytypes
|
1564 |
+
/// @{
|
1565 |
+
class bytearray : public object {
|
1566 |
+
public:
|
1567 |
+
PYBIND11_OBJECT_CVT(bytearray, object, PyByteArray_Check, PyByteArray_FromObject)
|
1568 |
+
|
1569 |
+
template <typename SzType, detail::enable_if_t<std::is_integral<SzType>::value, int> = 0>
|
1570 |
+
bytearray(const char *c, const SzType &n)
|
1571 |
+
: object(PyByteArray_FromStringAndSize(c, ssize_t_cast(n)), stolen_t{}) {
|
1572 |
+
if (!m_ptr) {
|
1573 |
+
pybind11_fail("Could not allocate bytearray object!");
|
1574 |
+
}
|
1575 |
+
}
|
1576 |
+
|
1577 |
+
bytearray() : bytearray("", 0) {}
|
1578 |
+
|
1579 |
+
explicit bytearray(const std::string &s) : bytearray(s.data(), s.size()) {}
|
1580 |
+
|
1581 |
+
size_t size() const { return static_cast<size_t>(PyByteArray_Size(m_ptr)); }
|
1582 |
+
|
1583 |
+
explicit operator std::string() const {
|
1584 |
+
char *buffer = PyByteArray_AS_STRING(m_ptr);
|
1585 |
+
ssize_t size = PyByteArray_GET_SIZE(m_ptr);
|
1586 |
+
return std::string(buffer, static_cast<size_t>(size));
|
1587 |
+
}
|
1588 |
+
};
|
1589 |
+
// Note: breathe >= 4.17.0 will fail to build docs if the below two constructors
|
1590 |
+
// are included in the doxygen group; close here and reopen after as a workaround
|
1591 |
+
/// @} pytypes
|
1592 |
+
|
1593 |
+
/// \addtogroup pytypes
|
1594 |
+
/// @{
|
1595 |
+
class none : public object {
|
1596 |
+
public:
|
1597 |
+
PYBIND11_OBJECT(none, object, detail::PyNone_Check)
|
1598 |
+
none() : object(Py_None, borrowed_t{}) {}
|
1599 |
+
};
|
1600 |
+
|
1601 |
+
class ellipsis : public object {
|
1602 |
+
public:
|
1603 |
+
PYBIND11_OBJECT(ellipsis, object, detail::PyEllipsis_Check)
|
1604 |
+
ellipsis() : object(Py_Ellipsis, borrowed_t{}) {}
|
1605 |
+
};
|
1606 |
+
|
1607 |
+
class bool_ : public object {
|
1608 |
+
public:
|
1609 |
+
PYBIND11_OBJECT_CVT(bool_, object, PyBool_Check, raw_bool)
|
1610 |
+
bool_() : object(Py_False, borrowed_t{}) {}
|
1611 |
+
// Allow implicit conversion from and to `bool`:
|
1612 |
+
// NOLINTNEXTLINE(google-explicit-constructor)
|
1613 |
+
bool_(bool value) : object(value ? Py_True : Py_False, borrowed_t{}) {}
|
1614 |
+
// NOLINTNEXTLINE(google-explicit-constructor)
|
1615 |
+
operator bool() const { return (m_ptr != nullptr) && PyLong_AsLong(m_ptr) != 0; }
|
1616 |
+
|
1617 |
+
private:
|
1618 |
+
/// Return the truth value of an object -- always returns a new reference
|
1619 |
+
static PyObject *raw_bool(PyObject *op) {
|
1620 |
+
const auto value = PyObject_IsTrue(op);
|
1621 |
+
if (value == -1) {
|
1622 |
+
return nullptr;
|
1623 |
+
}
|
1624 |
+
return handle(value != 0 ? Py_True : Py_False).inc_ref().ptr();
|
1625 |
+
}
|
1626 |
+
};
|
1627 |
+
|
1628 |
+
PYBIND11_NAMESPACE_BEGIN(detail)
|
1629 |
+
// Converts a value to the given unsigned type. If an error occurs, you get back (Unsigned) -1;
|
1630 |
+
// otherwise you get back the unsigned long or unsigned long long value cast to (Unsigned).
|
1631 |
+
// (The distinction is critically important when casting a returned -1 error value to some other
|
1632 |
+
// unsigned type: (A)-1 != (B)-1 when A and B are unsigned types of different sizes).
|
1633 |
+
template <typename Unsigned>
|
1634 |
+
Unsigned as_unsigned(PyObject *o) {
|
1635 |
+
if (PYBIND11_SILENCE_MSVC_C4127(sizeof(Unsigned) <= sizeof(unsigned long))) {
|
1636 |
+
unsigned long v = PyLong_AsUnsignedLong(o);
|
1637 |
+
return v == (unsigned long) -1 && PyErr_Occurred() ? (Unsigned) -1 : (Unsigned) v;
|
1638 |
+
}
|
1639 |
+
unsigned long long v = PyLong_AsUnsignedLongLong(o);
|
1640 |
+
return v == (unsigned long long) -1 && PyErr_Occurred() ? (Unsigned) -1 : (Unsigned) v;
|
1641 |
+
}
|
1642 |
+
PYBIND11_NAMESPACE_END(detail)
|
1643 |
+
|
1644 |
+
class int_ : public object {
|
1645 |
+
public:
|
1646 |
+
PYBIND11_OBJECT_CVT(int_, object, PYBIND11_LONG_CHECK, PyNumber_Long)
|
1647 |
+
int_() : object(PyLong_FromLong(0), stolen_t{}) {}
|
1648 |
+
// Allow implicit conversion from C++ integral types:
|
1649 |
+
template <typename T, detail::enable_if_t<std::is_integral<T>::value, int> = 0>
|
1650 |
+
// NOLINTNEXTLINE(google-explicit-constructor)
|
1651 |
+
int_(T value) {
|
1652 |
+
if (PYBIND11_SILENCE_MSVC_C4127(sizeof(T) <= sizeof(long))) {
|
1653 |
+
if (std::is_signed<T>::value) {
|
1654 |
+
m_ptr = PyLong_FromLong((long) value);
|
1655 |
+
} else {
|
1656 |
+
m_ptr = PyLong_FromUnsignedLong((unsigned long) value);
|
1657 |
+
}
|
1658 |
+
} else {
|
1659 |
+
if (std::is_signed<T>::value) {
|
1660 |
+
m_ptr = PyLong_FromLongLong((long long) value);
|
1661 |
+
} else {
|
1662 |
+
m_ptr = PyLong_FromUnsignedLongLong((unsigned long long) value);
|
1663 |
+
}
|
1664 |
+
}
|
1665 |
+
if (!m_ptr) {
|
1666 |
+
pybind11_fail("Could not allocate int object!");
|
1667 |
+
}
|
1668 |
+
}
|
1669 |
+
|
1670 |
+
template <typename T, detail::enable_if_t<std::is_integral<T>::value, int> = 0>
|
1671 |
+
// NOLINTNEXTLINE(google-explicit-constructor)
|
1672 |
+
operator T() const {
|
1673 |
+
return std::is_unsigned<T>::value ? detail::as_unsigned<T>(m_ptr)
|
1674 |
+
: sizeof(T) <= sizeof(long) ? (T) PyLong_AsLong(m_ptr)
|
1675 |
+
: (T) PYBIND11_LONG_AS_LONGLONG(m_ptr);
|
1676 |
+
}
|
1677 |
+
};
|
1678 |
+
|
1679 |
+
class float_ : public object {
|
1680 |
+
public:
|
1681 |
+
PYBIND11_OBJECT_CVT(float_, object, PyFloat_Check, PyNumber_Float)
|
1682 |
+
// Allow implicit conversion from float/double:
|
1683 |
+
// NOLINTNEXTLINE(google-explicit-constructor)
|
1684 |
+
float_(float value) : object(PyFloat_FromDouble((double) value), stolen_t{}) {
|
1685 |
+
if (!m_ptr) {
|
1686 |
+
pybind11_fail("Could not allocate float object!");
|
1687 |
+
}
|
1688 |
+
}
|
1689 |
+
// NOLINTNEXTLINE(google-explicit-constructor)
|
1690 |
+
float_(double value = .0) : object(PyFloat_FromDouble((double) value), stolen_t{}) {
|
1691 |
+
if (!m_ptr) {
|
1692 |
+
pybind11_fail("Could not allocate float object!");
|
1693 |
+
}
|
1694 |
+
}
|
1695 |
+
// NOLINTNEXTLINE(google-explicit-constructor)
|
1696 |
+
operator float() const { return (float) PyFloat_AsDouble(m_ptr); }
|
1697 |
+
// NOLINTNEXTLINE(google-explicit-constructor)
|
1698 |
+
operator double() const { return (double) PyFloat_AsDouble(m_ptr); }
|
1699 |
+
};
|
1700 |
+
|
1701 |
+
class weakref : public object {
|
1702 |
+
public:
|
1703 |
+
PYBIND11_OBJECT_CVT_DEFAULT(weakref, object, PyWeakref_Check, raw_weakref)
|
1704 |
+
explicit weakref(handle obj, handle callback = {})
|
1705 |
+
: object(PyWeakref_NewRef(obj.ptr(), callback.ptr()), stolen_t{}) {
|
1706 |
+
if (!m_ptr) {
|
1707 |
+
if (PyErr_Occurred()) {
|
1708 |
+
throw error_already_set();
|
1709 |
+
}
|
1710 |
+
pybind11_fail("Could not allocate weak reference!");
|
1711 |
+
}
|
1712 |
+
}
|
1713 |
+
|
1714 |
+
private:
|
1715 |
+
static PyObject *raw_weakref(PyObject *o) { return PyWeakref_NewRef(o, nullptr); }
|
1716 |
+
};
|
1717 |
+
|
1718 |
+
class slice : public object {
|
1719 |
+
public:
|
1720 |
+
PYBIND11_OBJECT_DEFAULT(slice, object, PySlice_Check)
|
1721 |
+
slice(handle start, handle stop, handle step)
|
1722 |
+
: object(PySlice_New(start.ptr(), stop.ptr(), step.ptr()), stolen_t{}) {
|
1723 |
+
if (!m_ptr) {
|
1724 |
+
pybind11_fail("Could not allocate slice object!");
|
1725 |
+
}
|
1726 |
+
}
|
1727 |
+
|
1728 |
+
#ifdef PYBIND11_HAS_OPTIONAL
|
1729 |
+
slice(std::optional<ssize_t> start, std::optional<ssize_t> stop, std::optional<ssize_t> step)
|
1730 |
+
: slice(index_to_object(start), index_to_object(stop), index_to_object(step)) {}
|
1731 |
+
#else
|
1732 |
+
slice(ssize_t start_, ssize_t stop_, ssize_t step_)
|
1733 |
+
: slice(int_(start_), int_(stop_), int_(step_)) {}
|
1734 |
+
#endif
|
1735 |
+
|
1736 |
+
bool
|
1737 |
+
compute(size_t length, size_t *start, size_t *stop, size_t *step, size_t *slicelength) const {
|
1738 |
+
return PySlice_GetIndicesEx((PYBIND11_SLICE_OBJECT *) m_ptr,
|
1739 |
+
(ssize_t) length,
|
1740 |
+
(ssize_t *) start,
|
1741 |
+
(ssize_t *) stop,
|
1742 |
+
(ssize_t *) step,
|
1743 |
+
(ssize_t *) slicelength)
|
1744 |
+
== 0;
|
1745 |
+
}
|
1746 |
+
bool compute(
|
1747 |
+
ssize_t length, ssize_t *start, ssize_t *stop, ssize_t *step, ssize_t *slicelength) const {
|
1748 |
+
return PySlice_GetIndicesEx(
|
1749 |
+
(PYBIND11_SLICE_OBJECT *) m_ptr, length, start, stop, step, slicelength)
|
1750 |
+
== 0;
|
1751 |
+
}
|
1752 |
+
|
1753 |
+
private:
|
1754 |
+
template <typename T>
|
1755 |
+
static object index_to_object(T index) {
|
1756 |
+
return index ? object(int_(*index)) : object(none());
|
1757 |
+
}
|
1758 |
+
};
|
1759 |
+
|
1760 |
+
class capsule : public object {
|
1761 |
+
public:
|
1762 |
+
PYBIND11_OBJECT_DEFAULT(capsule, object, PyCapsule_CheckExact)
|
1763 |
+
PYBIND11_DEPRECATED("Use reinterpret_borrow<capsule>() or reinterpret_steal<capsule>()")
|
1764 |
+
capsule(PyObject *ptr, bool is_borrowed)
|
1765 |
+
: object(is_borrowed ? object(ptr, borrowed_t{}) : object(ptr, stolen_t{})) {}
|
1766 |
+
|
1767 |
+
explicit capsule(const void *value,
|
1768 |
+
const char *name = nullptr,
|
1769 |
+
void (*destructor)(PyObject *) = nullptr)
|
1770 |
+
: object(PyCapsule_New(const_cast<void *>(value), name, destructor), stolen_t{}) {
|
1771 |
+
if (!m_ptr) {
|
1772 |
+
throw error_already_set();
|
1773 |
+
}
|
1774 |
+
}
|
1775 |
+
|
1776 |
+
PYBIND11_DEPRECATED("Please pass a destructor that takes a void pointer as input")
|
1777 |
+
capsule(const void *value, void (*destruct)(PyObject *))
|
1778 |
+
: object(PyCapsule_New(const_cast<void *>(value), nullptr, destruct), stolen_t{}) {
|
1779 |
+
if (!m_ptr) {
|
1780 |
+
throw error_already_set();
|
1781 |
+
}
|
1782 |
+
}
|
1783 |
+
|
1784 |
+
capsule(const void *value, void (*destructor)(void *)) {
|
1785 |
+
m_ptr = PyCapsule_New(const_cast<void *>(value), nullptr, [](PyObject *o) {
|
1786 |
+
// guard if destructor called while err indicator is set
|
1787 |
+
error_scope error_guard;
|
1788 |
+
auto destructor = reinterpret_cast<void (*)(void *)>(PyCapsule_GetContext(o));
|
1789 |
+
if (destructor == nullptr) {
|
1790 |
+
if (PyErr_Occurred()) {
|
1791 |
+
throw error_already_set();
|
1792 |
+
}
|
1793 |
+
pybind11_fail("Unable to get capsule context");
|
1794 |
+
}
|
1795 |
+
const char *name = get_name_in_error_scope(o);
|
1796 |
+
void *ptr = PyCapsule_GetPointer(o, name);
|
1797 |
+
if (ptr == nullptr) {
|
1798 |
+
throw error_already_set();
|
1799 |
+
}
|
1800 |
+
destructor(ptr);
|
1801 |
+
});
|
1802 |
+
|
1803 |
+
if (!m_ptr || PyCapsule_SetContext(m_ptr, (void *) destructor) != 0) {
|
1804 |
+
throw error_already_set();
|
1805 |
+
}
|
1806 |
+
}
|
1807 |
+
|
1808 |
+
explicit capsule(void (*destructor)()) {
|
1809 |
+
m_ptr = PyCapsule_New(reinterpret_cast<void *>(destructor), nullptr, [](PyObject *o) {
|
1810 |
+
const char *name = get_name_in_error_scope(o);
|
1811 |
+
auto destructor = reinterpret_cast<void (*)()>(PyCapsule_GetPointer(o, name));
|
1812 |
+
if (destructor == nullptr) {
|
1813 |
+
throw error_already_set();
|
1814 |
+
}
|
1815 |
+
destructor();
|
1816 |
+
});
|
1817 |
+
|
1818 |
+
if (!m_ptr) {
|
1819 |
+
throw error_already_set();
|
1820 |
+
}
|
1821 |
+
}
|
1822 |
+
|
1823 |
+
template <typename T>
|
1824 |
+
operator T *() const { // NOLINT(google-explicit-constructor)
|
1825 |
+
return get_pointer<T>();
|
1826 |
+
}
|
1827 |
+
|
1828 |
+
/// Get the pointer the capsule holds.
|
1829 |
+
template <typename T = void>
|
1830 |
+
T *get_pointer() const {
|
1831 |
+
const auto *name = this->name();
|
1832 |
+
T *result = static_cast<T *>(PyCapsule_GetPointer(m_ptr, name));
|
1833 |
+
if (!result) {
|
1834 |
+
throw error_already_set();
|
1835 |
+
}
|
1836 |
+
return result;
|
1837 |
+
}
|
1838 |
+
|
1839 |
+
/// Replaces a capsule's pointer *without* calling the destructor on the existing one.
|
1840 |
+
void set_pointer(const void *value) {
|
1841 |
+
if (PyCapsule_SetPointer(m_ptr, const_cast<void *>(value)) != 0) {
|
1842 |
+
throw error_already_set();
|
1843 |
+
}
|
1844 |
+
}
|
1845 |
+
|
1846 |
+
const char *name() const {
|
1847 |
+
const char *name = PyCapsule_GetName(m_ptr);
|
1848 |
+
if ((name == nullptr) && PyErr_Occurred()) {
|
1849 |
+
throw error_already_set();
|
1850 |
+
}
|
1851 |
+
return name;
|
1852 |
+
}
|
1853 |
+
|
1854 |
+
/// Replaces a capsule's name *without* calling the destructor on the existing one.
|
1855 |
+
void set_name(const char *new_name) {
|
1856 |
+
if (PyCapsule_SetName(m_ptr, new_name) != 0) {
|
1857 |
+
throw error_already_set();
|
1858 |
+
}
|
1859 |
+
}
|
1860 |
+
|
1861 |
+
private:
|
1862 |
+
static const char *get_name_in_error_scope(PyObject *o) {
|
1863 |
+
error_scope error_guard;
|
1864 |
+
|
1865 |
+
const char *name = PyCapsule_GetName(o);
|
1866 |
+
if ((name == nullptr) && PyErr_Occurred()) {
|
1867 |
+
// write out and consume error raised by call to PyCapsule_GetName
|
1868 |
+
PyErr_WriteUnraisable(o);
|
1869 |
+
}
|
1870 |
+
|
1871 |
+
return name;
|
1872 |
+
}
|
1873 |
+
};
|
1874 |
+
|
1875 |
+
class tuple : public object {
|
1876 |
+
public:
|
1877 |
+
PYBIND11_OBJECT_CVT(tuple, object, PyTuple_Check, PySequence_Tuple)
|
1878 |
+
template <typename SzType = ssize_t,
|
1879 |
+
detail::enable_if_t<std::is_integral<SzType>::value, int> = 0>
|
1880 |
+
// Some compilers generate link errors when using `const SzType &` here:
|
1881 |
+
explicit tuple(SzType size = 0) : object(PyTuple_New(ssize_t_cast(size)), stolen_t{}) {
|
1882 |
+
if (!m_ptr) {
|
1883 |
+
pybind11_fail("Could not allocate tuple object!");
|
1884 |
+
}
|
1885 |
+
}
|
1886 |
+
size_t size() const { return (size_t) PyTuple_Size(m_ptr); }
|
1887 |
+
bool empty() const { return size() == 0; }
|
1888 |
+
detail::tuple_accessor operator[](size_t index) const { return {*this, index}; }
|
1889 |
+
template <typename T, detail::enable_if_t<detail::is_pyobject<T>::value, int> = 0>
|
1890 |
+
detail::item_accessor operator[](T &&o) const {
|
1891 |
+
return object::operator[](std::forward<T>(o));
|
1892 |
+
}
|
1893 |
+
detail::tuple_iterator begin() const { return {*this, 0}; }
|
1894 |
+
detail::tuple_iterator end() const { return {*this, PyTuple_GET_SIZE(m_ptr)}; }
|
1895 |
+
};
|
1896 |
+
|
1897 |
+
// We need to put this into a separate function because the Intel compiler
|
1898 |
+
// fails to compile enable_if_t<all_of<is_keyword_or_ds<Args>...>::value> part below
|
1899 |
+
// (tested with ICC 2021.1 Beta 20200827).
|
1900 |
+
template <typename... Args>
|
1901 |
+
constexpr bool args_are_all_keyword_or_ds() {
|
1902 |
+
return detail::all_of<detail::is_keyword_or_ds<Args>...>::value;
|
1903 |
+
}
|
1904 |
+
|
1905 |
+
class dict : public object {
|
1906 |
+
public:
|
1907 |
+
PYBIND11_OBJECT_CVT(dict, object, PyDict_Check, raw_dict)
|
1908 |
+
dict() : object(PyDict_New(), stolen_t{}) {
|
1909 |
+
if (!m_ptr) {
|
1910 |
+
pybind11_fail("Could not allocate dict object!");
|
1911 |
+
}
|
1912 |
+
}
|
1913 |
+
template <typename... Args,
|
1914 |
+
typename = detail::enable_if_t<args_are_all_keyword_or_ds<Args...>()>,
|
1915 |
+
// MSVC workaround: it can't compile an out-of-line definition, so defer the
|
1916 |
+
// collector
|
1917 |
+
typename collector = detail::deferred_t<detail::unpacking_collector<>, Args...>>
|
1918 |
+
explicit dict(Args &&...args) : dict(collector(std::forward<Args>(args)...).kwargs()) {}
|
1919 |
+
|
1920 |
+
size_t size() const { return (size_t) PyDict_Size(m_ptr); }
|
1921 |
+
bool empty() const { return size() == 0; }
|
1922 |
+
detail::dict_iterator begin() const { return {*this, 0}; }
|
1923 |
+
detail::dict_iterator end() const { return {}; }
|
1924 |
+
void clear() /* py-non-const */ { PyDict_Clear(ptr()); }
|
1925 |
+
template <typename T>
|
1926 |
+
bool contains(T &&key) const {
|
1927 |
+
return PyDict_Contains(m_ptr, detail::object_or_cast(std::forward<T>(key)).ptr()) == 1;
|
1928 |
+
}
|
1929 |
+
|
1930 |
+
private:
|
1931 |
+
/// Call the `dict` Python type -- always returns a new reference
|
1932 |
+
static PyObject *raw_dict(PyObject *op) {
|
1933 |
+
if (PyDict_Check(op)) {
|
1934 |
+
return handle(op).inc_ref().ptr();
|
1935 |
+
}
|
1936 |
+
return PyObject_CallFunctionObjArgs((PyObject *) &PyDict_Type, op, nullptr);
|
1937 |
+
}
|
1938 |
+
};
|
1939 |
+
|
1940 |
+
class sequence : public object {
|
1941 |
+
public:
|
1942 |
+
PYBIND11_OBJECT_DEFAULT(sequence, object, PySequence_Check)
|
1943 |
+
size_t size() const {
|
1944 |
+
ssize_t result = PySequence_Size(m_ptr);
|
1945 |
+
if (result == -1) {
|
1946 |
+
throw error_already_set();
|
1947 |
+
}
|
1948 |
+
return (size_t) result;
|
1949 |
+
}
|
1950 |
+
bool empty() const { return size() == 0; }
|
1951 |
+
detail::sequence_accessor operator[](size_t index) const { return {*this, index}; }
|
1952 |
+
template <typename T, detail::enable_if_t<detail::is_pyobject<T>::value, int> = 0>
|
1953 |
+
detail::item_accessor operator[](T &&o) const {
|
1954 |
+
return object::operator[](std::forward<T>(o));
|
1955 |
+
}
|
1956 |
+
detail::sequence_iterator begin() const { return {*this, 0}; }
|
1957 |
+
detail::sequence_iterator end() const { return {*this, PySequence_Size(m_ptr)}; }
|
1958 |
+
};
|
1959 |
+
|
1960 |
+
class list : public object {
|
1961 |
+
public:
|
1962 |
+
PYBIND11_OBJECT_CVT(list, object, PyList_Check, PySequence_List)
|
1963 |
+
template <typename SzType = ssize_t,
|
1964 |
+
detail::enable_if_t<std::is_integral<SzType>::value, int> = 0>
|
1965 |
+
// Some compilers generate link errors when using `const SzType &` here:
|
1966 |
+
explicit list(SzType size = 0) : object(PyList_New(ssize_t_cast(size)), stolen_t{}) {
|
1967 |
+
if (!m_ptr) {
|
1968 |
+
pybind11_fail("Could not allocate list object!");
|
1969 |
+
}
|
1970 |
+
}
|
1971 |
+
size_t size() const { return (size_t) PyList_Size(m_ptr); }
|
1972 |
+
bool empty() const { return size() == 0; }
|
1973 |
+
detail::list_accessor operator[](size_t index) const { return {*this, index}; }
|
1974 |
+
template <typename T, detail::enable_if_t<detail::is_pyobject<T>::value, int> = 0>
|
1975 |
+
detail::item_accessor operator[](T &&o) const {
|
1976 |
+
return object::operator[](std::forward<T>(o));
|
1977 |
+
}
|
1978 |
+
detail::list_iterator begin() const { return {*this, 0}; }
|
1979 |
+
detail::list_iterator end() const { return {*this, PyList_GET_SIZE(m_ptr)}; }
|
1980 |
+
template <typename T>
|
1981 |
+
void append(T &&val) /* py-non-const */ {
|
1982 |
+
PyList_Append(m_ptr, detail::object_or_cast(std::forward<T>(val)).ptr());
|
1983 |
+
}
|
1984 |
+
template <typename IdxType,
|
1985 |
+
typename ValType,
|
1986 |
+
detail::enable_if_t<std::is_integral<IdxType>::value, int> = 0>
|
1987 |
+
void insert(const IdxType &index, ValType &&val) /* py-non-const */ {
|
1988 |
+
PyList_Insert(
|
1989 |
+
m_ptr, ssize_t_cast(index), detail::object_or_cast(std::forward<ValType>(val)).ptr());
|
1990 |
+
}
|
1991 |
+
};
|
1992 |
+
|
1993 |
+
class args : public tuple {
|
1994 |
+
PYBIND11_OBJECT_DEFAULT(args, tuple, PyTuple_Check)
|
1995 |
+
};
|
1996 |
+
class kwargs : public dict {
|
1997 |
+
PYBIND11_OBJECT_DEFAULT(kwargs, dict, PyDict_Check)
|
1998 |
+
};
|
1999 |
+
|
2000 |
+
class anyset : public object {
|
2001 |
+
public:
|
2002 |
+
PYBIND11_OBJECT(anyset, object, PyAnySet_Check)
|
2003 |
+
size_t size() const { return static_cast<size_t>(PySet_Size(m_ptr)); }
|
2004 |
+
bool empty() const { return size() == 0; }
|
2005 |
+
template <typename T>
|
2006 |
+
bool contains(T &&val) const {
|
2007 |
+
return PySet_Contains(m_ptr, detail::object_or_cast(std::forward<T>(val)).ptr()) == 1;
|
2008 |
+
}
|
2009 |
+
};
|
2010 |
+
|
2011 |
+
class set : public anyset {
|
2012 |
+
public:
|
2013 |
+
PYBIND11_OBJECT_CVT(set, anyset, PySet_Check, PySet_New)
|
2014 |
+
set() : anyset(PySet_New(nullptr), stolen_t{}) {
|
2015 |
+
if (!m_ptr) {
|
2016 |
+
pybind11_fail("Could not allocate set object!");
|
2017 |
+
}
|
2018 |
+
}
|
2019 |
+
template <typename T>
|
2020 |
+
bool add(T &&val) /* py-non-const */ {
|
2021 |
+
return PySet_Add(m_ptr, detail::object_or_cast(std::forward<T>(val)).ptr()) == 0;
|
2022 |
+
}
|
2023 |
+
void clear() /* py-non-const */ { PySet_Clear(m_ptr); }
|
2024 |
+
};
|
2025 |
+
|
2026 |
+
class frozenset : public anyset {
|
2027 |
+
public:
|
2028 |
+
PYBIND11_OBJECT_CVT(frozenset, anyset, PyFrozenSet_Check, PyFrozenSet_New)
|
2029 |
+
};
|
2030 |
+
|
2031 |
+
class function : public object {
|
2032 |
+
public:
|
2033 |
+
PYBIND11_OBJECT_DEFAULT(function, object, PyCallable_Check)
|
2034 |
+
handle cpp_function() const {
|
2035 |
+
handle fun = detail::get_function(m_ptr);
|
2036 |
+
if (fun && PyCFunction_Check(fun.ptr())) {
|
2037 |
+
return fun;
|
2038 |
+
}
|
2039 |
+
return handle();
|
2040 |
+
}
|
2041 |
+
bool is_cpp_function() const { return (bool) cpp_function(); }
|
2042 |
+
};
|
2043 |
+
|
2044 |
+
class staticmethod : public object {
|
2045 |
+
public:
|
2046 |
+
PYBIND11_OBJECT_CVT(staticmethod, object, detail::PyStaticMethod_Check, PyStaticMethod_New)
|
2047 |
+
};
|
2048 |
+
|
2049 |
+
class buffer : public object {
|
2050 |
+
public:
|
2051 |
+
PYBIND11_OBJECT_DEFAULT(buffer, object, PyObject_CheckBuffer)
|
2052 |
+
|
2053 |
+
buffer_info request(bool writable = false) const {
|
2054 |
+
int flags = PyBUF_STRIDES | PyBUF_FORMAT;
|
2055 |
+
if (writable) {
|
2056 |
+
flags |= PyBUF_WRITABLE;
|
2057 |
+
}
|
2058 |
+
auto *view = new Py_buffer();
|
2059 |
+
if (PyObject_GetBuffer(m_ptr, view, flags) != 0) {
|
2060 |
+
delete view;
|
2061 |
+
throw error_already_set();
|
2062 |
+
}
|
2063 |
+
return buffer_info(view);
|
2064 |
+
}
|
2065 |
+
};
|
2066 |
+
|
2067 |
+
class memoryview : public object {
|
2068 |
+
public:
|
2069 |
+
PYBIND11_OBJECT_CVT(memoryview, object, PyMemoryView_Check, PyMemoryView_FromObject)
|
2070 |
+
|
2071 |
+
/** \rst
|
2072 |
+
Creates ``memoryview`` from ``buffer_info``.
|
2073 |
+
|
2074 |
+
``buffer_info`` must be created from ``buffer::request()``. Otherwise
|
2075 |
+
throws an exception.
|
2076 |
+
|
2077 |
+
For creating a ``memoryview`` from objects that support buffer protocol,
|
2078 |
+
use ``memoryview(const object& obj)`` instead of this constructor.
|
2079 |
+
\endrst */
|
2080 |
+
explicit memoryview(const buffer_info &info) {
|
2081 |
+
if (!info.view()) {
|
2082 |
+
pybind11_fail("Prohibited to create memoryview without Py_buffer");
|
2083 |
+
}
|
2084 |
+
// Note: PyMemoryView_FromBuffer never increments obj reference.
|
2085 |
+
m_ptr = (info.view()->obj) ? PyMemoryView_FromObject(info.view()->obj)
|
2086 |
+
: PyMemoryView_FromBuffer(info.view());
|
2087 |
+
if (!m_ptr) {
|
2088 |
+
pybind11_fail("Unable to create memoryview from buffer descriptor");
|
2089 |
+
}
|
2090 |
+
}
|
2091 |
+
|
2092 |
+
/** \rst
|
2093 |
+
Creates ``memoryview`` from static buffer.
|
2094 |
+
|
2095 |
+
This method is meant for providing a ``memoryview`` for C/C++ buffer not
|
2096 |
+
managed by Python. The caller is responsible for managing the lifetime
|
2097 |
+
of ``ptr`` and ``format``, which MUST outlive the memoryview constructed
|
2098 |
+
here.
|
2099 |
+
|
2100 |
+
See also: Python C API documentation for `PyMemoryView_FromBuffer`_.
|
2101 |
+
|
2102 |
+
.. _PyMemoryView_FromBuffer:
|
2103 |
+
https://docs.python.org/c-api/memoryview.html#c.PyMemoryView_FromBuffer
|
2104 |
+
|
2105 |
+
:param ptr: Pointer to the buffer.
|
2106 |
+
:param itemsize: Byte size of an element.
|
2107 |
+
:param format: Pointer to the null-terminated format string. For
|
2108 |
+
homogeneous Buffers, this should be set to
|
2109 |
+
``format_descriptor<T>::value``.
|
2110 |
+
:param shape: Shape of the tensor (1 entry per dimension).
|
2111 |
+
:param strides: Number of bytes between adjacent entries (for each
|
2112 |
+
per dimension).
|
2113 |
+
:param readonly: Flag to indicate if the underlying storage may be
|
2114 |
+
written to.
|
2115 |
+
\endrst */
|
2116 |
+
static memoryview from_buffer(void *ptr,
|
2117 |
+
ssize_t itemsize,
|
2118 |
+
const char *format,
|
2119 |
+
detail::any_container<ssize_t> shape,
|
2120 |
+
detail::any_container<ssize_t> strides,
|
2121 |
+
bool readonly = false);
|
2122 |
+
|
2123 |
+
static memoryview from_buffer(const void *ptr,
|
2124 |
+
ssize_t itemsize,
|
2125 |
+
const char *format,
|
2126 |
+
detail::any_container<ssize_t> shape,
|
2127 |
+
detail::any_container<ssize_t> strides) {
|
2128 |
+
return memoryview::from_buffer(
|
2129 |
+
const_cast<void *>(ptr), itemsize, format, std::move(shape), std::move(strides), true);
|
2130 |
+
}
|
2131 |
+
|
2132 |
+
template <typename T>
|
2133 |
+
static memoryview from_buffer(T *ptr,
|
2134 |
+
detail::any_container<ssize_t> shape,
|
2135 |
+
detail::any_container<ssize_t> strides,
|
2136 |
+
bool readonly = false) {
|
2137 |
+
return memoryview::from_buffer(reinterpret_cast<void *>(ptr),
|
2138 |
+
sizeof(T),
|
2139 |
+
format_descriptor<T>::value,
|
2140 |
+
std::move(shape),
|
2141 |
+
std::move(strides),
|
2142 |
+
readonly);
|
2143 |
+
}
|
2144 |
+
|
2145 |
+
template <typename T>
|
2146 |
+
static memoryview from_buffer(const T *ptr,
|
2147 |
+
detail::any_container<ssize_t> shape,
|
2148 |
+
detail::any_container<ssize_t> strides) {
|
2149 |
+
return memoryview::from_buffer(
|
2150 |
+
const_cast<T *>(ptr), std::move(shape), std::move(strides), true);
|
2151 |
+
}
|
2152 |
+
|
2153 |
+
/** \rst
|
2154 |
+
Creates ``memoryview`` from static memory.
|
2155 |
+
|
2156 |
+
This method is meant for providing a ``memoryview`` for C/C++ buffer not
|
2157 |
+
managed by Python. The caller is responsible for managing the lifetime
|
2158 |
+
of ``mem``, which MUST outlive the memoryview constructed here.
|
2159 |
+
|
2160 |
+
See also: Python C API documentation for `PyMemoryView_FromBuffer`_.
|
2161 |
+
|
2162 |
+
.. _PyMemoryView_FromMemory:
|
2163 |
+
https://docs.python.org/c-api/memoryview.html#c.PyMemoryView_FromMemory
|
2164 |
+
\endrst */
|
2165 |
+
static memoryview from_memory(void *mem, ssize_t size, bool readonly = false) {
|
2166 |
+
PyObject *ptr = PyMemoryView_FromMemory(
|
2167 |
+
reinterpret_cast<char *>(mem), size, (readonly) ? PyBUF_READ : PyBUF_WRITE);
|
2168 |
+
if (!ptr) {
|
2169 |
+
pybind11_fail("Could not allocate memoryview object!");
|
2170 |
+
}
|
2171 |
+
return memoryview(object(ptr, stolen_t{}));
|
2172 |
+
}
|
2173 |
+
|
2174 |
+
static memoryview from_memory(const void *mem, ssize_t size) {
|
2175 |
+
return memoryview::from_memory(const_cast<void *>(mem), size, true);
|
2176 |
+
}
|
2177 |
+
|
2178 |
+
#ifdef PYBIND11_HAS_STRING_VIEW
|
2179 |
+
static memoryview from_memory(std::string_view mem) {
|
2180 |
+
return from_memory(const_cast<char *>(mem.data()), static_cast<ssize_t>(mem.size()), true);
|
2181 |
+
}
|
2182 |
+
#endif
|
2183 |
+
};
|
2184 |
+
|
2185 |
+
/// @cond DUPLICATE
|
2186 |
+
inline memoryview memoryview::from_buffer(void *ptr,
|
2187 |
+
ssize_t itemsize,
|
2188 |
+
const char *format,
|
2189 |
+
detail::any_container<ssize_t> shape,
|
2190 |
+
detail::any_container<ssize_t> strides,
|
2191 |
+
bool readonly) {
|
2192 |
+
size_t ndim = shape->size();
|
2193 |
+
if (ndim != strides->size()) {
|
2194 |
+
pybind11_fail("memoryview: shape length doesn't match strides length");
|
2195 |
+
}
|
2196 |
+
ssize_t size = ndim != 0u ? 1 : 0;
|
2197 |
+
for (size_t i = 0; i < ndim; ++i) {
|
2198 |
+
size *= (*shape)[i];
|
2199 |
+
}
|
2200 |
+
Py_buffer view;
|
2201 |
+
view.buf = ptr;
|
2202 |
+
view.obj = nullptr;
|
2203 |
+
view.len = size * itemsize;
|
2204 |
+
view.readonly = static_cast<int>(readonly);
|
2205 |
+
view.itemsize = itemsize;
|
2206 |
+
view.format = const_cast<char *>(format);
|
2207 |
+
view.ndim = static_cast<int>(ndim);
|
2208 |
+
view.shape = shape->data();
|
2209 |
+
view.strides = strides->data();
|
2210 |
+
view.suboffsets = nullptr;
|
2211 |
+
view.internal = nullptr;
|
2212 |
+
PyObject *obj = PyMemoryView_FromBuffer(&view);
|
2213 |
+
if (!obj) {
|
2214 |
+
throw error_already_set();
|
2215 |
+
}
|
2216 |
+
return memoryview(object(obj, stolen_t{}));
|
2217 |
+
}
|
2218 |
+
/// @endcond
|
2219 |
+
/// @} pytypes
|
2220 |
+
|
2221 |
+
/// \addtogroup python_builtins
|
2222 |
+
/// @{
|
2223 |
+
|
2224 |
+
/// Get the length of a Python object.
|
2225 |
+
inline size_t len(handle h) {
|
2226 |
+
ssize_t result = PyObject_Length(h.ptr());
|
2227 |
+
if (result < 0) {
|
2228 |
+
throw error_already_set();
|
2229 |
+
}
|
2230 |
+
return (size_t) result;
|
2231 |
+
}
|
2232 |
+
|
2233 |
+
/// Get the length hint of a Python object.
|
2234 |
+
/// Returns 0 when this cannot be determined.
|
2235 |
+
inline size_t len_hint(handle h) {
|
2236 |
+
ssize_t result = PyObject_LengthHint(h.ptr(), 0);
|
2237 |
+
if (result < 0) {
|
2238 |
+
// Sometimes a length can't be determined at all (eg generators)
|
2239 |
+
// In which case simply return 0
|
2240 |
+
PyErr_Clear();
|
2241 |
+
return 0;
|
2242 |
+
}
|
2243 |
+
return (size_t) result;
|
2244 |
+
}
|
2245 |
+
|
2246 |
+
inline str repr(handle h) {
|
2247 |
+
PyObject *str_value = PyObject_Repr(h.ptr());
|
2248 |
+
if (!str_value) {
|
2249 |
+
throw error_already_set();
|
2250 |
+
}
|
2251 |
+
return reinterpret_steal<str>(str_value);
|
2252 |
+
}
|
2253 |
+
|
2254 |
+
inline iterator iter(handle obj) {
|
2255 |
+
PyObject *result = PyObject_GetIter(obj.ptr());
|
2256 |
+
if (!result) {
|
2257 |
+
throw error_already_set();
|
2258 |
+
}
|
2259 |
+
return reinterpret_steal<iterator>(result);
|
2260 |
+
}
|
2261 |
+
/// @} python_builtins
|
2262 |
+
|
2263 |
+
PYBIND11_NAMESPACE_BEGIN(detail)
|
2264 |
+
template <typename D>
|
2265 |
+
iterator object_api<D>::begin() const {
|
2266 |
+
return iter(derived());
|
2267 |
+
}
|
2268 |
+
template <typename D>
|
2269 |
+
iterator object_api<D>::end() const {
|
2270 |
+
return iterator::sentinel();
|
2271 |
+
}
|
2272 |
+
template <typename D>
|
2273 |
+
item_accessor object_api<D>::operator[](handle key) const {
|
2274 |
+
return {derived(), reinterpret_borrow<object>(key)};
|
2275 |
+
}
|
2276 |
+
template <typename D>
|
2277 |
+
item_accessor object_api<D>::operator[](object &&key) const {
|
2278 |
+
return {derived(), std::move(key)};
|
2279 |
+
}
|
2280 |
+
template <typename D>
|
2281 |
+
item_accessor object_api<D>::operator[](const char *key) const {
|
2282 |
+
return {derived(), pybind11::str(key)};
|
2283 |
+
}
|
2284 |
+
template <typename D>
|
2285 |
+
obj_attr_accessor object_api<D>::attr(handle key) const {
|
2286 |
+
return {derived(), reinterpret_borrow<object>(key)};
|
2287 |
+
}
|
2288 |
+
template <typename D>
|
2289 |
+
obj_attr_accessor object_api<D>::attr(object &&key) const {
|
2290 |
+
return {derived(), std::move(key)};
|
2291 |
+
}
|
2292 |
+
template <typename D>
|
2293 |
+
str_attr_accessor object_api<D>::attr(const char *key) const {
|
2294 |
+
return {derived(), key};
|
2295 |
+
}
|
2296 |
+
template <typename D>
|
2297 |
+
args_proxy object_api<D>::operator*() const {
|
2298 |
+
return args_proxy(derived().ptr());
|
2299 |
+
}
|
2300 |
+
template <typename D>
|
2301 |
+
template <typename T>
|
2302 |
+
bool object_api<D>::contains(T &&item) const {
|
2303 |
+
return attr("__contains__")(std::forward<T>(item)).template cast<bool>();
|
2304 |
+
}
|
2305 |
+
|
2306 |
+
template <typename D>
|
2307 |
+
pybind11::str object_api<D>::str() const {
|
2308 |
+
return pybind11::str(derived());
|
2309 |
+
}
|
2310 |
+
|
2311 |
+
template <typename D>
|
2312 |
+
str_attr_accessor object_api<D>::doc() const {
|
2313 |
+
return attr("__doc__");
|
2314 |
+
}
|
2315 |
+
|
2316 |
+
template <typename D>
|
2317 |
+
handle object_api<D>::get_type() const {
|
2318 |
+
return type::handle_of(derived());
|
2319 |
+
}
|
2320 |
+
|
2321 |
+
template <typename D>
|
2322 |
+
bool object_api<D>::rich_compare(object_api const &other, int value) const {
|
2323 |
+
int rv = PyObject_RichCompareBool(derived().ptr(), other.derived().ptr(), value);
|
2324 |
+
if (rv == -1) {
|
2325 |
+
throw error_already_set();
|
2326 |
+
}
|
2327 |
+
return rv == 1;
|
2328 |
+
}
|
2329 |
+
|
2330 |
+
#define PYBIND11_MATH_OPERATOR_UNARY(op, fn) \
|
2331 |
+
template <typename D> \
|
2332 |
+
object object_api<D>::op() const { \
|
2333 |
+
object result = reinterpret_steal<object>(fn(derived().ptr())); \
|
2334 |
+
if (!result.ptr()) \
|
2335 |
+
throw error_already_set(); \
|
2336 |
+
return result; \
|
2337 |
+
}
|
2338 |
+
|
2339 |
+
#define PYBIND11_MATH_OPERATOR_BINARY(op, fn) \
|
2340 |
+
template <typename D> \
|
2341 |
+
object object_api<D>::op(object_api const &other) const { \
|
2342 |
+
object result = reinterpret_steal<object>(fn(derived().ptr(), other.derived().ptr())); \
|
2343 |
+
if (!result.ptr()) \
|
2344 |
+
throw error_already_set(); \
|
2345 |
+
return result; \
|
2346 |
+
}
|
2347 |
+
|
2348 |
+
PYBIND11_MATH_OPERATOR_UNARY(operator~, PyNumber_Invert)
|
2349 |
+
PYBIND11_MATH_OPERATOR_UNARY(operator-, PyNumber_Negative)
|
2350 |
+
PYBIND11_MATH_OPERATOR_BINARY(operator+, PyNumber_Add)
|
2351 |
+
PYBIND11_MATH_OPERATOR_BINARY(operator+=, PyNumber_InPlaceAdd)
|
2352 |
+
PYBIND11_MATH_OPERATOR_BINARY(operator-, PyNumber_Subtract)
|
2353 |
+
PYBIND11_MATH_OPERATOR_BINARY(operator-=, PyNumber_InPlaceSubtract)
|
2354 |
+
PYBIND11_MATH_OPERATOR_BINARY(operator*, PyNumber_Multiply)
|
2355 |
+
PYBIND11_MATH_OPERATOR_BINARY(operator*=, PyNumber_InPlaceMultiply)
|
2356 |
+
PYBIND11_MATH_OPERATOR_BINARY(operator/, PyNumber_TrueDivide)
|
2357 |
+
PYBIND11_MATH_OPERATOR_BINARY(operator/=, PyNumber_InPlaceTrueDivide)
|
2358 |
+
PYBIND11_MATH_OPERATOR_BINARY(operator|, PyNumber_Or)
|
2359 |
+
PYBIND11_MATH_OPERATOR_BINARY(operator|=, PyNumber_InPlaceOr)
|
2360 |
+
PYBIND11_MATH_OPERATOR_BINARY(operator&, PyNumber_And)
|
2361 |
+
PYBIND11_MATH_OPERATOR_BINARY(operator&=, PyNumber_InPlaceAnd)
|
2362 |
+
PYBIND11_MATH_OPERATOR_BINARY(operator^, PyNumber_Xor)
|
2363 |
+
PYBIND11_MATH_OPERATOR_BINARY(operator^=, PyNumber_InPlaceXor)
|
2364 |
+
PYBIND11_MATH_OPERATOR_BINARY(operator<<, PyNumber_Lshift)
|
2365 |
+
PYBIND11_MATH_OPERATOR_BINARY(operator<<=, PyNumber_InPlaceLshift)
|
2366 |
+
PYBIND11_MATH_OPERATOR_BINARY(operator>>, PyNumber_Rshift)
|
2367 |
+
PYBIND11_MATH_OPERATOR_BINARY(operator>>=, PyNumber_InPlaceRshift)
|
2368 |
+
|
2369 |
+
#undef PYBIND11_MATH_OPERATOR_UNARY
|
2370 |
+
#undef PYBIND11_MATH_OPERATOR_BINARY
|
2371 |
+
|
2372 |
+
PYBIND11_NAMESPACE_END(detail)
|
2373 |
+
PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)
|
third-party/DPVO/DPViewer/pybind11/include/pybind11/stl.h
ADDED
@@ -0,0 +1,425 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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 "detail/common.h"
|
14 |
+
|
15 |
+
#include <deque>
|
16 |
+
#include <list>
|
17 |
+
#include <map>
|
18 |
+
#include <ostream>
|
19 |
+
#include <set>
|
20 |
+
#include <unordered_map>
|
21 |
+
#include <unordered_set>
|
22 |
+
#include <valarray>
|
23 |
+
|
24 |
+
// See `detail/common.h` for implementation of these guards.
|
25 |
+
#if defined(PYBIND11_HAS_OPTIONAL)
|
26 |
+
# include <optional>
|
27 |
+
#elif defined(PYBIND11_HAS_EXP_OPTIONAL)
|
28 |
+
# include <experimental/optional>
|
29 |
+
#endif
|
30 |
+
|
31 |
+
#if defined(PYBIND11_HAS_VARIANT)
|
32 |
+
# include <variant>
|
33 |
+
#endif
|
34 |
+
|
35 |
+
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
|
36 |
+
PYBIND11_NAMESPACE_BEGIN(detail)
|
37 |
+
|
38 |
+
/// Extracts an const lvalue reference or rvalue reference for U based on the type of T (e.g. for
|
39 |
+
/// forwarding a container element). Typically used indirect via forwarded_type(), below.
|
40 |
+
template <typename T, typename U>
|
41 |
+
using forwarded_type = conditional_t<std::is_lvalue_reference<T>::value,
|
42 |
+
remove_reference_t<U> &,
|
43 |
+
remove_reference_t<U> &&>;
|
44 |
+
|
45 |
+
/// Forwards a value U as rvalue or lvalue according to whether T is rvalue or lvalue; typically
|
46 |
+
/// used for forwarding a container's elements.
|
47 |
+
template <typename T, typename U>
|
48 |
+
forwarded_type<T, U> forward_like(U &&u) {
|
49 |
+
return std::forward<detail::forwarded_type<T, U>>(std::forward<U>(u));
|
50 |
+
}
|
51 |
+
|
52 |
+
template <typename Type, typename Key>
|
53 |
+
struct set_caster {
|
54 |
+
using type = Type;
|
55 |
+
using key_conv = make_caster<Key>;
|
56 |
+
|
57 |
+
bool load(handle src, bool convert) {
|
58 |
+
if (!isinstance<anyset>(src)) {
|
59 |
+
return false;
|
60 |
+
}
|
61 |
+
auto s = reinterpret_borrow<anyset>(src);
|
62 |
+
value.clear();
|
63 |
+
for (auto entry : s) {
|
64 |
+
key_conv conv;
|
65 |
+
if (!conv.load(entry, convert)) {
|
66 |
+
return false;
|
67 |
+
}
|
68 |
+
value.insert(cast_op<Key &&>(std::move(conv)));
|
69 |
+
}
|
70 |
+
return true;
|
71 |
+
}
|
72 |
+
|
73 |
+
template <typename T>
|
74 |
+
static handle cast(T &&src, return_value_policy policy, handle parent) {
|
75 |
+
if (!std::is_lvalue_reference<T>::value) {
|
76 |
+
policy = return_value_policy_override<Key>::policy(policy);
|
77 |
+
}
|
78 |
+
pybind11::set s;
|
79 |
+
for (auto &&value : src) {
|
80 |
+
auto value_ = reinterpret_steal<object>(
|
81 |
+
key_conv::cast(forward_like<T>(value), policy, parent));
|
82 |
+
if (!value_ || !s.add(std::move(value_))) {
|
83 |
+
return handle();
|
84 |
+
}
|
85 |
+
}
|
86 |
+
return s.release();
|
87 |
+
}
|
88 |
+
|
89 |
+
PYBIND11_TYPE_CASTER(type, const_name("Set[") + key_conv::name + const_name("]"));
|
90 |
+
};
|
91 |
+
|
92 |
+
template <typename Type, typename Key, typename Value>
|
93 |
+
struct map_caster {
|
94 |
+
using key_conv = make_caster<Key>;
|
95 |
+
using value_conv = make_caster<Value>;
|
96 |
+
|
97 |
+
bool load(handle src, bool convert) {
|
98 |
+
if (!isinstance<dict>(src)) {
|
99 |
+
return false;
|
100 |
+
}
|
101 |
+
auto d = reinterpret_borrow<dict>(src);
|
102 |
+
value.clear();
|
103 |
+
for (auto it : d) {
|
104 |
+
key_conv kconv;
|
105 |
+
value_conv vconv;
|
106 |
+
if (!kconv.load(it.first.ptr(), convert) || !vconv.load(it.second.ptr(), convert)) {
|
107 |
+
return false;
|
108 |
+
}
|
109 |
+
value.emplace(cast_op<Key &&>(std::move(kconv)), cast_op<Value &&>(std::move(vconv)));
|
110 |
+
}
|
111 |
+
return true;
|
112 |
+
}
|
113 |
+
|
114 |
+
template <typename T>
|
115 |
+
static handle cast(T &&src, return_value_policy policy, handle parent) {
|
116 |
+
dict d;
|
117 |
+
return_value_policy policy_key = policy;
|
118 |
+
return_value_policy policy_value = policy;
|
119 |
+
if (!std::is_lvalue_reference<T>::value) {
|
120 |
+
policy_key = return_value_policy_override<Key>::policy(policy_key);
|
121 |
+
policy_value = return_value_policy_override<Value>::policy(policy_value);
|
122 |
+
}
|
123 |
+
for (auto &&kv : src) {
|
124 |
+
auto key = reinterpret_steal<object>(
|
125 |
+
key_conv::cast(forward_like<T>(kv.first), policy_key, parent));
|
126 |
+
auto value = reinterpret_steal<object>(
|
127 |
+
value_conv::cast(forward_like<T>(kv.second), policy_value, parent));
|
128 |
+
if (!key || !value) {
|
129 |
+
return handle();
|
130 |
+
}
|
131 |
+
d[std::move(key)] = std::move(value);
|
132 |
+
}
|
133 |
+
return d.release();
|
134 |
+
}
|
135 |
+
|
136 |
+
PYBIND11_TYPE_CASTER(Type,
|
137 |
+
const_name("Dict[") + key_conv::name + const_name(", ") + value_conv::name
|
138 |
+
+ const_name("]"));
|
139 |
+
};
|
140 |
+
|
141 |
+
template <typename Type, typename Value>
|
142 |
+
struct list_caster {
|
143 |
+
using value_conv = make_caster<Value>;
|
144 |
+
|
145 |
+
bool load(handle src, bool convert) {
|
146 |
+
if (!isinstance<sequence>(src) || isinstance<bytes>(src) || isinstance<str>(src)) {
|
147 |
+
return false;
|
148 |
+
}
|
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 |
+
}
|
157 |
+
value.push_back(cast_op<Value &&>(std::move(conv)));
|
158 |
+
}
|
159 |
+
return true;
|
160 |
+
}
|
161 |
+
|
162 |
+
private:
|
163 |
+
template <
|
164 |
+
typename T = Type,
|
165 |
+
enable_if_t<std::is_same<decltype(std::declval<T>().reserve(0)), void>::value, int> = 0>
|
166 |
+
void reserve_maybe(const sequence &s, Type *) {
|
167 |
+
value.reserve(s.size());
|
168 |
+
}
|
169 |
+
void reserve_maybe(const sequence &, void *) {}
|
170 |
+
|
171 |
+
public:
|
172 |
+
template <typename T>
|
173 |
+
static handle cast(T &&src, return_value_policy policy, handle parent) {
|
174 |
+
if (!std::is_lvalue_reference<T>::value) {
|
175 |
+
policy = return_value_policy_override<Value>::policy(policy);
|
176 |
+
}
|
177 |
+
list l(src.size());
|
178 |
+
ssize_t index = 0;
|
179 |
+
for (auto &&value : src) {
|
180 |
+
auto value_ = reinterpret_steal<object>(
|
181 |
+
value_conv::cast(forward_like<T>(value), policy, parent));
|
182 |
+
if (!value_) {
|
183 |
+
return handle();
|
184 |
+
}
|
185 |
+
PyList_SET_ITEM(l.ptr(), index++, value_.release().ptr()); // steals a reference
|
186 |
+
}
|
187 |
+
return l.release();
|
188 |
+
}
|
189 |
+
|
190 |
+
PYBIND11_TYPE_CASTER(Type, const_name("List[") + value_conv::name + const_name("]"));
|
191 |
+
};
|
192 |
+
|
193 |
+
template <typename Type, typename Alloc>
|
194 |
+
struct type_caster<std::vector<Type, Alloc>> : list_caster<std::vector<Type, Alloc>, Type> {};
|
195 |
+
|
196 |
+
template <typename Type, typename Alloc>
|
197 |
+
struct type_caster<std::deque<Type, Alloc>> : list_caster<std::deque<Type, Alloc>, Type> {};
|
198 |
+
|
199 |
+
template <typename Type, typename Alloc>
|
200 |
+
struct type_caster<std::list<Type, Alloc>> : list_caster<std::list<Type, Alloc>, Type> {};
|
201 |
+
|
202 |
+
template <typename ArrayType, typename Value, bool Resizable, size_t Size = 0>
|
203 |
+
struct array_caster {
|
204 |
+
using value_conv = make_caster<Value>;
|
205 |
+
|
206 |
+
private:
|
207 |
+
template <bool R = Resizable>
|
208 |
+
bool require_size(enable_if_t<R, size_t> size) {
|
209 |
+
if (value.size() != size) {
|
210 |
+
value.resize(size);
|
211 |
+
}
|
212 |
+
return true;
|
213 |
+
}
|
214 |
+
template <bool R = Resizable>
|
215 |
+
bool require_size(enable_if_t<!R, size_t> size) {
|
216 |
+
return size == Size;
|
217 |
+
}
|
218 |
+
|
219 |
+
public:
|
220 |
+
bool load(handle src, bool convert) {
|
221 |
+
if (!isinstance<sequence>(src)) {
|
222 |
+
return false;
|
223 |
+
}
|
224 |
+
auto l = reinterpret_borrow<sequence>(src);
|
225 |
+
if (!require_size(l.size())) {
|
226 |
+
return false;
|
227 |
+
}
|
228 |
+
size_t ctr = 0;
|
229 |
+
for (auto it : l) {
|
230 |
+
value_conv conv;
|
231 |
+
if (!conv.load(it, convert)) {
|
232 |
+
return false;
|
233 |
+
}
|
234 |
+
value[ctr++] = cast_op<Value &&>(std::move(conv));
|
235 |
+
}
|
236 |
+
return true;
|
237 |
+
}
|
238 |
+
|
239 |
+
template <typename T>
|
240 |
+
static handle cast(T &&src, return_value_policy policy, handle parent) {
|
241 |
+
list l(src.size());
|
242 |
+
ssize_t index = 0;
|
243 |
+
for (auto &&value : src) {
|
244 |
+
auto value_ = reinterpret_steal<object>(
|
245 |
+
value_conv::cast(forward_like<T>(value), policy, parent));
|
246 |
+
if (!value_) {
|
247 |
+
return handle();
|
248 |
+
}
|
249 |
+
PyList_SET_ITEM(l.ptr(), index++, value_.release().ptr()); // steals a reference
|
250 |
+
}
|
251 |
+
return l.release();
|
252 |
+
}
|
253 |
+
|
254 |
+
PYBIND11_TYPE_CASTER(ArrayType,
|
255 |
+
const_name("List[") + value_conv::name
|
256 |
+
+ const_name<Resizable>(const_name(""),
|
257 |
+
const_name("[") + const_name<Size>()
|
258 |
+
+ const_name("]"))
|
259 |
+
+ const_name("]"));
|
260 |
+
};
|
261 |
+
|
262 |
+
template <typename Type, size_t Size>
|
263 |
+
struct type_caster<std::array<Type, Size>>
|
264 |
+
: array_caster<std::array<Type, Size>, Type, false, Size> {};
|
265 |
+
|
266 |
+
template <typename Type>
|
267 |
+
struct type_caster<std::valarray<Type>> : array_caster<std::valarray<Type>, Type, true> {};
|
268 |
+
|
269 |
+
template <typename Key, typename Compare, typename Alloc>
|
270 |
+
struct type_caster<std::set<Key, Compare, Alloc>>
|
271 |
+
: set_caster<std::set<Key, Compare, Alloc>, Key> {};
|
272 |
+
|
273 |
+
template <typename Key, typename Hash, typename Equal, typename Alloc>
|
274 |
+
struct type_caster<std::unordered_set<Key, Hash, Equal, Alloc>>
|
275 |
+
: set_caster<std::unordered_set<Key, Hash, Equal, Alloc>, Key> {};
|
276 |
+
|
277 |
+
template <typename Key, typename Value, typename Compare, typename Alloc>
|
278 |
+
struct type_caster<std::map<Key, Value, Compare, Alloc>>
|
279 |
+
: map_caster<std::map<Key, Value, Compare, Alloc>, Key, Value> {};
|
280 |
+
|
281 |
+
template <typename Key, typename Value, typename Hash, typename Equal, typename Alloc>
|
282 |
+
struct type_caster<std::unordered_map<Key, Value, Hash, Equal, Alloc>>
|
283 |
+
: map_caster<std::unordered_map<Key, Value, Hash, Equal, Alloc>, Key, Value> {};
|
284 |
+
|
285 |
+
// This type caster is intended to be used for std::optional and std::experimental::optional
|
286 |
+
template <typename Type, typename Value = typename Type::value_type>
|
287 |
+
struct optional_caster {
|
288 |
+
using value_conv = make_caster<Value>;
|
289 |
+
|
290 |
+
template <typename T>
|
291 |
+
static handle cast(T &&src, return_value_policy policy, handle parent) {
|
292 |
+
if (!src) {
|
293 |
+
return none().inc_ref();
|
294 |
+
}
|
295 |
+
if (!std::is_lvalue_reference<T>::value) {
|
296 |
+
policy = return_value_policy_override<Value>::policy(policy);
|
297 |
+
}
|
298 |
+
return value_conv::cast(*std::forward<T>(src), policy, parent);
|
299 |
+
}
|
300 |
+
|
301 |
+
bool load(handle src, bool convert) {
|
302 |
+
if (!src) {
|
303 |
+
return false;
|
304 |
+
}
|
305 |
+
if (src.is_none()) {
|
306 |
+
return true; // default-constructed value is already empty
|
307 |
+
}
|
308 |
+
value_conv inner_caster;
|
309 |
+
if (!inner_caster.load(src, convert)) {
|
310 |
+
return false;
|
311 |
+
}
|
312 |
+
|
313 |
+
value.emplace(cast_op<Value &&>(std::move(inner_caster)));
|
314 |
+
return true;
|
315 |
+
}
|
316 |
+
|
317 |
+
PYBIND11_TYPE_CASTER(Type, const_name("Optional[") + value_conv::name + const_name("]"));
|
318 |
+
};
|
319 |
+
|
320 |
+
#if defined(PYBIND11_HAS_OPTIONAL)
|
321 |
+
template <typename T>
|
322 |
+
struct type_caster<std::optional<T>> : public optional_caster<std::optional<T>> {};
|
323 |
+
|
324 |
+
template <>
|
325 |
+
struct type_caster<std::nullopt_t> : public void_caster<std::nullopt_t> {};
|
326 |
+
#endif
|
327 |
+
|
328 |
+
#if defined(PYBIND11_HAS_EXP_OPTIONAL)
|
329 |
+
template <typename T>
|
330 |
+
struct type_caster<std::experimental::optional<T>>
|
331 |
+
: public optional_caster<std::experimental::optional<T>> {};
|
332 |
+
|
333 |
+
template <>
|
334 |
+
struct type_caster<std::experimental::nullopt_t>
|
335 |
+
: public void_caster<std::experimental::nullopt_t> {};
|
336 |
+
#endif
|
337 |
+
|
338 |
+
/// Visit a variant and cast any found type to Python
|
339 |
+
struct variant_caster_visitor {
|
340 |
+
return_value_policy policy;
|
341 |
+
handle parent;
|
342 |
+
|
343 |
+
using result_type = handle; // required by boost::variant in C++11
|
344 |
+
|
345 |
+
template <typename T>
|
346 |
+
result_type operator()(T &&src) const {
|
347 |
+
return make_caster<T>::cast(std::forward<T>(src), policy, parent);
|
348 |
+
}
|
349 |
+
};
|
350 |
+
|
351 |
+
/// Helper class which abstracts away variant's `visit` function. `std::variant` and similar
|
352 |
+
/// `namespace::variant` types which provide a `namespace::visit()` function are handled here
|
353 |
+
/// automatically using argument-dependent lookup. Users can provide specializations for other
|
354 |
+
/// variant-like classes, e.g. `boost::variant` and `boost::apply_visitor`.
|
355 |
+
template <template <typename...> class Variant>
|
356 |
+
struct visit_helper {
|
357 |
+
template <typename... Args>
|
358 |
+
static auto call(Args &&...args) -> decltype(visit(std::forward<Args>(args)...)) {
|
359 |
+
return visit(std::forward<Args>(args)...);
|
360 |
+
}
|
361 |
+
};
|
362 |
+
|
363 |
+
/// Generic variant caster
|
364 |
+
template <typename Variant>
|
365 |
+
struct variant_caster;
|
366 |
+
|
367 |
+
template <template <typename...> class V, typename... Ts>
|
368 |
+
struct variant_caster<V<Ts...>> {
|
369 |
+
static_assert(sizeof...(Ts) > 0, "Variant must consist of at least one alternative.");
|
370 |
+
|
371 |
+
template <typename U, typename... Us>
|
372 |
+
bool load_alternative(handle src, bool convert, type_list<U, Us...>) {
|
373 |
+
auto caster = make_caster<U>();
|
374 |
+
if (caster.load(src, convert)) {
|
375 |
+
value = cast_op<U>(std::move(caster));
|
376 |
+
return true;
|
377 |
+
}
|
378 |
+
return load_alternative(src, convert, type_list<Us...>{});
|
379 |
+
}
|
380 |
+
|
381 |
+
bool load_alternative(handle, bool, type_list<>) { return false; }
|
382 |
+
|
383 |
+
bool load(handle src, bool convert) {
|
384 |
+
// Do a first pass without conversions to improve constructor resolution.
|
385 |
+
// E.g. `py::int_(1).cast<variant<double, int>>()` needs to fill the `int`
|
386 |
+
// slot of the variant. Without two-pass loading `double` would be filled
|
387 |
+
// because it appears first and a conversion is possible.
|
388 |
+
if (convert && load_alternative(src, false, type_list<Ts...>{})) {
|
389 |
+
return true;
|
390 |
+
}
|
391 |
+
return load_alternative(src, convert, type_list<Ts...>{});
|
392 |
+
}
|
393 |
+
|
394 |
+
template <typename Variant>
|
395 |
+
static handle cast(Variant &&src, return_value_policy policy, handle parent) {
|
396 |
+
return visit_helper<V>::call(variant_caster_visitor{policy, parent},
|
397 |
+
std::forward<Variant>(src));
|
398 |
+
}
|
399 |
+
|
400 |
+
using Type = V<Ts...>;
|
401 |
+
PYBIND11_TYPE_CASTER(Type,
|
402 |
+
const_name("Union[") + detail::concat(make_caster<Ts>::name...)
|
403 |
+
+ const_name("]"));
|
404 |
+
};
|
405 |
+
|
406 |
+
#if defined(PYBIND11_HAS_VARIANT)
|
407 |
+
template <typename... Ts>
|
408 |
+
struct type_caster<std::variant<Ts...>> : variant_caster<std::variant<Ts...>> {};
|
409 |
+
|
410 |
+
template <>
|
411 |
+
struct type_caster<std::monostate> : public void_caster<std::monostate> {};
|
412 |
+
#endif
|
413 |
+
|
414 |
+
PYBIND11_NAMESPACE_END(detail)
|
415 |
+
|
416 |
+
inline std::ostream &operator<<(std::ostream &os, const handle &obj) {
|
417 |
+
#ifdef PYBIND11_HAS_STRING_VIEW
|
418 |
+
os << str(obj).cast<std::string_view>();
|
419 |
+
#else
|
420 |
+
os << (std::string) str(obj);
|
421 |
+
#endif
|
422 |
+
return os;
|
423 |
+
}
|
424 |
+
|
425 |
+
PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)
|
third-party/DPVO/DPViewer/pybind11/include/pybind11/stl/filesystem.h
ADDED
@@ -0,0 +1,116 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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 "../pybind11.h"
|
8 |
+
#include "../detail/common.h"
|
9 |
+
#include "../detail/descr.h"
|
10 |
+
#include "../cast.h"
|
11 |
+
#include "../pytypes.h"
|
12 |
+
|
13 |
+
#include <string>
|
14 |
+
|
15 |
+
#ifdef __has_include
|
16 |
+
# if defined(PYBIND11_CPP17)
|
17 |
+
# if __has_include(<filesystem>) && \
|
18 |
+
PY_VERSION_HEX >= 0x03060000
|
19 |
+
# include <filesystem>
|
20 |
+
# define PYBIND11_HAS_FILESYSTEM 1
|
21 |
+
# elif __has_include(<experimental/filesystem>)
|
22 |
+
# include <experimental/filesystem>
|
23 |
+
# define PYBIND11_HAS_EXPERIMENTAL_FILESYSTEM 1
|
24 |
+
# endif
|
25 |
+
# endif
|
26 |
+
#endif
|
27 |
+
|
28 |
+
#if !defined(PYBIND11_HAS_FILESYSTEM) && !defined(PYBIND11_HAS_EXPERIMENTAL_FILESYSTEM) \
|
29 |
+
&& !defined(PYBIND11_HAS_FILESYSTEM_IS_OPTIONAL)
|
30 |
+
# error \
|
31 |
+
"Neither #include <filesystem> nor #include <experimental/filesystem is available. (Use -DPYBIND11_HAS_FILESYSTEM_IS_OPTIONAL to ignore.)"
|
32 |
+
#endif
|
33 |
+
|
34 |
+
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
|
35 |
+
PYBIND11_NAMESPACE_BEGIN(detail)
|
36 |
+
|
37 |
+
#if defined(PYBIND11_HAS_FILESYSTEM) || defined(PYBIND11_HAS_EXPERIMENTAL_FILESYSTEM)
|
38 |
+
template <typename T>
|
39 |
+
struct path_caster {
|
40 |
+
|
41 |
+
private:
|
42 |
+
static PyObject *unicode_from_fs_native(const std::string &w) {
|
43 |
+
# if !defined(PYPY_VERSION)
|
44 |
+
return PyUnicode_DecodeFSDefaultAndSize(w.c_str(), ssize_t(w.size()));
|
45 |
+
# else
|
46 |
+
// PyPy mistakenly declares the first parameter as non-const.
|
47 |
+
return PyUnicode_DecodeFSDefaultAndSize(const_cast<char *>(w.c_str()), ssize_t(w.size()));
|
48 |
+
# endif
|
49 |
+
}
|
50 |
+
|
51 |
+
static PyObject *unicode_from_fs_native(const std::wstring &w) {
|
52 |
+
return PyUnicode_FromWideChar(w.c_str(), ssize_t(w.size()));
|
53 |
+
}
|
54 |
+
|
55 |
+
public:
|
56 |
+
static handle cast(const T &path, return_value_policy, handle) {
|
57 |
+
if (auto py_str = unicode_from_fs_native(path.native())) {
|
58 |
+
return module_::import("pathlib")
|
59 |
+
.attr("Path")(reinterpret_steal<object>(py_str))
|
60 |
+
.release();
|
61 |
+
}
|
62 |
+
return nullptr;
|
63 |
+
}
|
64 |
+
|
65 |
+
bool load(handle handle, bool) {
|
66 |
+
// PyUnicode_FSConverter and PyUnicode_FSDecoder normally take care of
|
67 |
+
// calling PyOS_FSPath themselves, but that's broken on PyPy (PyPy
|
68 |
+
// issue #3168) so we do it ourselves instead.
|
69 |
+
PyObject *buf = PyOS_FSPath(handle.ptr());
|
70 |
+
if (!buf) {
|
71 |
+
PyErr_Clear();
|
72 |
+
return false;
|
73 |
+
}
|
74 |
+
PyObject *native = nullptr;
|
75 |
+
if constexpr (std::is_same_v<typename T::value_type, char>) {
|
76 |
+
if (PyUnicode_FSConverter(buf, &native) != 0) {
|
77 |
+
if (auto *c_str = PyBytes_AsString(native)) {
|
78 |
+
// AsString returns a pointer to the internal buffer, which
|
79 |
+
// must not be free'd.
|
80 |
+
value = c_str;
|
81 |
+
}
|
82 |
+
}
|
83 |
+
} else if constexpr (std::is_same_v<typename T::value_type, wchar_t>) {
|
84 |
+
if (PyUnicode_FSDecoder(buf, &native) != 0) {
|
85 |
+
if (auto *c_str = PyUnicode_AsWideCharString(native, nullptr)) {
|
86 |
+
// AsWideCharString returns a new string that must be free'd.
|
87 |
+
value = c_str; // Copies the string.
|
88 |
+
PyMem_Free(c_str);
|
89 |
+
}
|
90 |
+
}
|
91 |
+
}
|
92 |
+
Py_XDECREF(native);
|
93 |
+
Py_DECREF(buf);
|
94 |
+
if (PyErr_Occurred()) {
|
95 |
+
PyErr_Clear();
|
96 |
+
return false;
|
97 |
+
}
|
98 |
+
return true;
|
99 |
+
}
|
100 |
+
|
101 |
+
PYBIND11_TYPE_CASTER(T, const_name("os.PathLike"));
|
102 |
+
};
|
103 |
+
|
104 |
+
#endif // PYBIND11_HAS_FILESYSTEM || defined(PYBIND11_HAS_EXPERIMENTAL_FILESYSTEM)
|
105 |
+
|
106 |
+
#if defined(PYBIND11_HAS_FILESYSTEM)
|
107 |
+
template <>
|
108 |
+
struct type_caster<std::filesystem::path> : public path_caster<std::filesystem::path> {};
|
109 |
+
#elif defined(PYBIND11_HAS_EXPERIMENTAL_FILESYSTEM)
|
110 |
+
template <>
|
111 |
+
struct type_caster<std::experimental::filesystem::path>
|
112 |
+
: public path_caster<std::experimental::filesystem::path> {};
|
113 |
+
#endif
|
114 |
+
|
115 |
+
PYBIND11_NAMESPACE_END(detail)
|
116 |
+
PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)
|
third-party/DPVO/DPViewer/pybind11/include/pybind11/stl_bind.h
ADDED
@@ -0,0 +1,785 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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>
|
23 |
+
struct container_traits {
|
24 |
+
template <typename T2>
|
25 |
+
static std::true_type
|
26 |
+
test_comparable(decltype(std::declval<const T2 &>() == std::declval<const T2 &>()) *);
|
27 |
+
template <typename T2>
|
28 |
+
static std::false_type test_comparable(...);
|
29 |
+
template <typename T2>
|
30 |
+
static std::true_type test_value(typename T2::value_type *);
|
31 |
+
template <typename T2>
|
32 |
+
static std::false_type test_value(...);
|
33 |
+
template <typename T2>
|
34 |
+
static std::true_type test_pair(typename T2::first_type *, typename T2::second_type *);
|
35 |
+
template <typename T2>
|
36 |
+
static std::false_type test_pair(...);
|
37 |
+
|
38 |
+
static constexpr const bool is_comparable
|
39 |
+
= std::is_same<std::true_type, decltype(test_comparable<T>(nullptr))>::value;
|
40 |
+
static constexpr const bool is_pair
|
41 |
+
= std::is_same<std::true_type, decltype(test_pair<T>(nullptr, nullptr))>::value;
|
42 |
+
static constexpr const bool is_vector
|
43 |
+
= std::is_same<std::true_type, decltype(test_value<T>(nullptr))>::value;
|
44 |
+
static constexpr const bool is_element = !is_pair && !is_vector;
|
45 |
+
};
|
46 |
+
|
47 |
+
/* Default: is_comparable -> std::false_type */
|
48 |
+
template <typename T, typename SFINAE = void>
|
49 |
+
struct is_comparable : std::false_type {};
|
50 |
+
|
51 |
+
/* For non-map data structures, check whether operator== can be instantiated */
|
52 |
+
template <typename T>
|
53 |
+
struct is_comparable<
|
54 |
+
T,
|
55 |
+
enable_if_t<container_traits<T>::is_element && container_traits<T>::is_comparable>>
|
56 |
+
: std::true_type {};
|
57 |
+
|
58 |
+
/* For a vector/map data structure, recursively check the value type
|
59 |
+
(which is std::pair for maps) */
|
60 |
+
template <typename T>
|
61 |
+
struct is_comparable<T, enable_if_t<container_traits<T>::is_vector>> {
|
62 |
+
static constexpr const bool value = is_comparable<typename T::value_type>::value;
|
63 |
+
};
|
64 |
+
|
65 |
+
/* For pairs, recursively check the two data types */
|
66 |
+
template <typename T>
|
67 |
+
struct is_comparable<T, enable_if_t<container_traits<T>::is_pair>> {
|
68 |
+
static constexpr const bool value = is_comparable<typename T::first_type>::value
|
69 |
+
&& is_comparable<typename T::second_type>::value;
|
70 |
+
};
|
71 |
+
|
72 |
+
/* Fallback functions */
|
73 |
+
template <typename, typename, typename... Args>
|
74 |
+
void vector_if_copy_constructible(const Args &...) {}
|
75 |
+
template <typename, typename, typename... Args>
|
76 |
+
void vector_if_equal_operator(const Args &...) {}
|
77 |
+
template <typename, typename, typename... Args>
|
78 |
+
void vector_if_insertion_operator(const Args &...) {}
|
79 |
+
template <typename, typename, typename... Args>
|
80 |
+
void vector_modifiers(const Args &...) {}
|
81 |
+
|
82 |
+
template <typename Vector, typename Class_>
|
83 |
+
void vector_if_copy_constructible(enable_if_t<is_copy_constructible<Vector>::value, Class_> &cl) {
|
84 |
+
cl.def(init<const Vector &>(), "Copy constructor");
|
85 |
+
}
|
86 |
+
|
87 |
+
template <typename Vector, typename Class_>
|
88 |
+
void vector_if_equal_operator(enable_if_t<is_comparable<Vector>::value, Class_> &cl) {
|
89 |
+
using T = typename Vector::value_type;
|
90 |
+
|
91 |
+
cl.def(self == self);
|
92 |
+
cl.def(self != self);
|
93 |
+
|
94 |
+
cl.def(
|
95 |
+
"count",
|
96 |
+
[](const Vector &v, const T &x) { return std::count(v.begin(), v.end(), x); },
|
97 |
+
arg("x"),
|
98 |
+
"Return the number of times ``x`` appears in the list");
|
99 |
+
|
100 |
+
cl.def(
|
101 |
+
"remove",
|
102 |
+
[](Vector &v, const T &x) {
|
103 |
+
auto p = std::find(v.begin(), v.end(), x);
|
104 |
+
if (p != v.end()) {
|
105 |
+
v.erase(p);
|
106 |
+
} else {
|
107 |
+
throw value_error();
|
108 |
+
}
|
109 |
+
},
|
110 |
+
arg("x"),
|
111 |
+
"Remove the first item from the list whose value is x. "
|
112 |
+
"It is an error if there is no such item.");
|
113 |
+
|
114 |
+
cl.def(
|
115 |
+
"__contains__",
|
116 |
+
[](const Vector &v, const T &x) { return std::find(v.begin(), v.end(), x) != v.end(); },
|
117 |
+
arg("x"),
|
118 |
+
"Return true the container contains ``x``");
|
119 |
+
}
|
120 |
+
|
121 |
+
// Vector modifiers -- requires a copyable vector_type:
|
122 |
+
// (Technically, some of these (pop and __delitem__) don't actually require copyability, but it
|
123 |
+
// seems silly to allow deletion but not insertion, so include them here too.)
|
124 |
+
template <typename Vector, typename Class_>
|
125 |
+
void vector_modifiers(
|
126 |
+
enable_if_t<is_copy_constructible<typename Vector::value_type>::value, Class_> &cl) {
|
127 |
+
using T = typename Vector::value_type;
|
128 |
+
using SizeType = typename Vector::size_type;
|
129 |
+
using DiffType = typename Vector::difference_type;
|
130 |
+
|
131 |
+
auto wrap_i = [](DiffType i, SizeType n) {
|
132 |
+
if (i < 0) {
|
133 |
+
i += n;
|
134 |
+
}
|
135 |
+
if (i < 0 || (SizeType) i >= n) {
|
136 |
+
throw index_error();
|
137 |
+
}
|
138 |
+
return i;
|
139 |
+
};
|
140 |
+
|
141 |
+
cl.def(
|
142 |
+
"append",
|
143 |
+
[](Vector &v, const T &value) { v.push_back(value); },
|
144 |
+
arg("x"),
|
145 |
+
"Add an item to the end of the list");
|
146 |
+
|
147 |
+
cl.def(init([](const iterable &it) {
|
148 |
+
auto v = std::unique_ptr<Vector>(new Vector());
|
149 |
+
v->reserve(len_hint(it));
|
150 |
+
for (handle h : it) {
|
151 |
+
v->push_back(h.cast<T>());
|
152 |
+
}
|
153 |
+
return v.release();
|
154 |
+
}));
|
155 |
+
|
156 |
+
cl.def(
|
157 |
+
"clear", [](Vector &v) { v.clear(); }, "Clear the contents");
|
158 |
+
|
159 |
+
cl.def(
|
160 |
+
"extend",
|
161 |
+
[](Vector &v, const Vector &src) { v.insert(v.end(), src.begin(), src.end()); },
|
162 |
+
arg("L"),
|
163 |
+
"Extend the list by appending all the items in the given list");
|
164 |
+
|
165 |
+
cl.def(
|
166 |
+
"extend",
|
167 |
+
[](Vector &v, const iterable &it) {
|
168 |
+
const size_t old_size = v.size();
|
169 |
+
v.reserve(old_size + len_hint(it));
|
170 |
+
try {
|
171 |
+
for (handle h : it) {
|
172 |
+
v.push_back(h.cast<T>());
|
173 |
+
}
|
174 |
+
} catch (const cast_error &) {
|
175 |
+
v.erase(v.begin() + static_cast<typename Vector::difference_type>(old_size),
|
176 |
+
v.end());
|
177 |
+
try {
|
178 |
+
v.shrink_to_fit();
|
179 |
+
} catch (const std::exception &) {
|
180 |
+
// Do nothing
|
181 |
+
}
|
182 |
+
throw;
|
183 |
+
}
|
184 |
+
},
|
185 |
+
arg("L"),
|
186 |
+
"Extend the list by appending all the items in the given list");
|
187 |
+
|
188 |
+
cl.def(
|
189 |
+
"insert",
|
190 |
+
[](Vector &v, DiffType i, const T &x) {
|
191 |
+
// Can't use wrap_i; i == v.size() is OK
|
192 |
+
if (i < 0) {
|
193 |
+
i += v.size();
|
194 |
+
}
|
195 |
+
if (i < 0 || (SizeType) i > v.size()) {
|
196 |
+
throw index_error();
|
197 |
+
}
|
198 |
+
v.insert(v.begin() + i, x);
|
199 |
+
},
|
200 |
+
arg("i"),
|
201 |
+
arg("x"),
|
202 |
+
"Insert an item at a given position.");
|
203 |
+
|
204 |
+
cl.def(
|
205 |
+
"pop",
|
206 |
+
[](Vector &v) {
|
207 |
+
if (v.empty()) {
|
208 |
+
throw index_error();
|
209 |
+
}
|
210 |
+
T t = std::move(v.back());
|
211 |
+
v.pop_back();
|
212 |
+
return t;
|
213 |
+
},
|
214 |
+
"Remove and return the last item");
|
215 |
+
|
216 |
+
cl.def(
|
217 |
+
"pop",
|
218 |
+
[wrap_i](Vector &v, DiffType i) {
|
219 |
+
i = wrap_i(i, v.size());
|
220 |
+
T t = std::move(v[(SizeType) i]);
|
221 |
+
v.erase(std::next(v.begin(), i));
|
222 |
+
return t;
|
223 |
+
},
|
224 |
+
arg("i"),
|
225 |
+
"Remove and return the item at index ``i``");
|
226 |
+
|
227 |
+
cl.def("__setitem__", [wrap_i](Vector &v, DiffType i, const T &t) {
|
228 |
+
i = wrap_i(i, v.size());
|
229 |
+
v[(SizeType) i] = t;
|
230 |
+
});
|
231 |
+
|
232 |
+
/// Slicing protocol
|
233 |
+
cl.def(
|
234 |
+
"__getitem__",
|
235 |
+
[](const Vector &v, const slice &slice) -> Vector * {
|
236 |
+
size_t start = 0, stop = 0, step = 0, slicelength = 0;
|
237 |
+
|
238 |
+
if (!slice.compute(v.size(), &start, &stop, &step, &slicelength)) {
|
239 |
+
throw error_already_set();
|
240 |
+
}
|
241 |
+
|
242 |
+
auto *seq = new Vector();
|
243 |
+
seq->reserve((size_t) slicelength);
|
244 |
+
|
245 |
+
for (size_t i = 0; i < slicelength; ++i) {
|
246 |
+
seq->push_back(v[start]);
|
247 |
+
start += step;
|
248 |
+
}
|
249 |
+
return seq;
|
250 |
+
},
|
251 |
+
arg("s"),
|
252 |
+
"Retrieve list elements using a slice object");
|
253 |
+
|
254 |
+
cl.def(
|
255 |
+
"__setitem__",
|
256 |
+
[](Vector &v, const slice &slice, const Vector &value) {
|
257 |
+
size_t start = 0, stop = 0, step = 0, slicelength = 0;
|
258 |
+
if (!slice.compute(v.size(), &start, &stop, &step, &slicelength)) {
|
259 |
+
throw error_already_set();
|
260 |
+
}
|
261 |
+
|
262 |
+
if (slicelength != value.size()) {
|
263 |
+
throw std::runtime_error(
|
264 |
+
"Left and right hand size of slice assignment have different sizes!");
|
265 |
+
}
|
266 |
+
|
267 |
+
for (size_t i = 0; i < slicelength; ++i) {
|
268 |
+
v[start] = value[i];
|
269 |
+
start += step;
|
270 |
+
}
|
271 |
+
},
|
272 |
+
"Assign list elements using a slice object");
|
273 |
+
|
274 |
+
cl.def(
|
275 |
+
"__delitem__",
|
276 |
+
[wrap_i](Vector &v, DiffType i) {
|
277 |
+
i = wrap_i(i, v.size());
|
278 |
+
v.erase(v.begin() + i);
|
279 |
+
},
|
280 |
+
"Delete the list elements at index ``i``");
|
281 |
+
|
282 |
+
cl.def(
|
283 |
+
"__delitem__",
|
284 |
+
[](Vector &v, const slice &slice) {
|
285 |
+
size_t start = 0, stop = 0, step = 0, slicelength = 0;
|
286 |
+
|
287 |
+
if (!slice.compute(v.size(), &start, &stop, &step, &slicelength)) {
|
288 |
+
throw error_already_set();
|
289 |
+
}
|
290 |
+
|
291 |
+
if (step == 1 && false) {
|
292 |
+
v.erase(v.begin() + (DiffType) start, v.begin() + DiffType(start + slicelength));
|
293 |
+
} else {
|
294 |
+
for (size_t i = 0; i < slicelength; ++i) {
|
295 |
+
v.erase(v.begin() + DiffType(start));
|
296 |
+
start += step - 1;
|
297 |
+
}
|
298 |
+
}
|
299 |
+
},
|
300 |
+
"Delete list elements using a slice object");
|
301 |
+
}
|
302 |
+
|
303 |
+
// If the type has an operator[] that doesn't return a reference (most notably std::vector<bool>),
|
304 |
+
// we have to access by copying; otherwise we return by reference.
|
305 |
+
template <typename Vector>
|
306 |
+
using vector_needs_copy
|
307 |
+
= negation<std::is_same<decltype(std::declval<Vector>()[typename Vector::size_type()]),
|
308 |
+
typename Vector::value_type &>>;
|
309 |
+
|
310 |
+
// The usual case: access and iterate by reference
|
311 |
+
template <typename Vector, typename Class_>
|
312 |
+
void vector_accessor(enable_if_t<!vector_needs_copy<Vector>::value, Class_> &cl) {
|
313 |
+
using T = typename Vector::value_type;
|
314 |
+
using SizeType = typename Vector::size_type;
|
315 |
+
using DiffType = typename Vector::difference_type;
|
316 |
+
using ItType = typename Vector::iterator;
|
317 |
+
|
318 |
+
auto wrap_i = [](DiffType i, SizeType n) {
|
319 |
+
if (i < 0) {
|
320 |
+
i += n;
|
321 |
+
}
|
322 |
+
if (i < 0 || (SizeType) i >= n) {
|
323 |
+
throw index_error();
|
324 |
+
}
|
325 |
+
return i;
|
326 |
+
};
|
327 |
+
|
328 |
+
cl.def(
|
329 |
+
"__getitem__",
|
330 |
+
[wrap_i](Vector &v, DiffType i) -> T & {
|
331 |
+
i = wrap_i(i, v.size());
|
332 |
+
return v[(SizeType) i];
|
333 |
+
},
|
334 |
+
return_value_policy::reference_internal // ref + keepalive
|
335 |
+
);
|
336 |
+
|
337 |
+
cl.def(
|
338 |
+
"__iter__",
|
339 |
+
[](Vector &v) {
|
340 |
+
return make_iterator<return_value_policy::reference_internal, ItType, ItType, T &>(
|
341 |
+
v.begin(), v.end());
|
342 |
+
},
|
343 |
+
keep_alive<0, 1>() /* Essential: keep list alive while iterator exists */
|
344 |
+
);
|
345 |
+
}
|
346 |
+
|
347 |
+
// The case for special objects, like std::vector<bool>, that have to be returned-by-copy:
|
348 |
+
template <typename Vector, typename Class_>
|
349 |
+
void vector_accessor(enable_if_t<vector_needs_copy<Vector>::value, Class_> &cl) {
|
350 |
+
using T = typename Vector::value_type;
|
351 |
+
using SizeType = typename Vector::size_type;
|
352 |
+
using DiffType = typename Vector::difference_type;
|
353 |
+
using ItType = typename Vector::iterator;
|
354 |
+
cl.def("__getitem__", [](const Vector &v, DiffType i) -> T {
|
355 |
+
if (i < 0 && (i += v.size()) < 0) {
|
356 |
+
throw index_error();
|
357 |
+
}
|
358 |
+
if ((SizeType) i >= v.size()) {
|
359 |
+
throw index_error();
|
360 |
+
}
|
361 |
+
return v[(SizeType) i];
|
362 |
+
});
|
363 |
+
|
364 |
+
cl.def(
|
365 |
+
"__iter__",
|
366 |
+
[](Vector &v) {
|
367 |
+
return make_iterator<return_value_policy::copy, ItType, ItType, T>(v.begin(), v.end());
|
368 |
+
},
|
369 |
+
keep_alive<0, 1>() /* Essential: keep list alive while iterator exists */
|
370 |
+
);
|
371 |
+
}
|
372 |
+
|
373 |
+
template <typename Vector, typename Class_>
|
374 |
+
auto vector_if_insertion_operator(Class_ &cl, std::string const &name)
|
375 |
+
-> decltype(std::declval<std::ostream &>() << std::declval<typename Vector::value_type>(),
|
376 |
+
void()) {
|
377 |
+
using size_type = typename Vector::size_type;
|
378 |
+
|
379 |
+
cl.def(
|
380 |
+
"__repr__",
|
381 |
+
[name](Vector &v) {
|
382 |
+
std::ostringstream s;
|
383 |
+
s << name << '[';
|
384 |
+
for (size_type i = 0; i < v.size(); ++i) {
|
385 |
+
s << v[i];
|
386 |
+
if (i != v.size() - 1) {
|
387 |
+
s << ", ";
|
388 |
+
}
|
389 |
+
}
|
390 |
+
s << ']';
|
391 |
+
return s.str();
|
392 |
+
},
|
393 |
+
"Return the canonical string representation of this list.");
|
394 |
+
}
|
395 |
+
|
396 |
+
// Provide the buffer interface for vectors if we have data() and we have a format for it
|
397 |
+
// GCC seems to have "void std::vector<bool>::data()" - doing SFINAE on the existence of data()
|
398 |
+
// is insufficient, we need to check it returns an appropriate pointer
|
399 |
+
template <typename Vector, typename = void>
|
400 |
+
struct vector_has_data_and_format : std::false_type {};
|
401 |
+
template <typename Vector>
|
402 |
+
struct vector_has_data_and_format<
|
403 |
+
Vector,
|
404 |
+
enable_if_t<std::is_same<decltype(format_descriptor<typename Vector::value_type>::format(),
|
405 |
+
std::declval<Vector>().data()),
|
406 |
+
typename Vector::value_type *>::value>> : std::true_type {};
|
407 |
+
|
408 |
+
// [workaround(intel)] Separate function required here
|
409 |
+
// Workaround as the Intel compiler does not compile the enable_if_t part below
|
410 |
+
// (tested with icc (ICC) 2021.1 Beta 20200827)
|
411 |
+
template <typename... Args>
|
412 |
+
constexpr bool args_any_are_buffer() {
|
413 |
+
return detail::any_of<std::is_same<Args, buffer_protocol>...>::value;
|
414 |
+
}
|
415 |
+
|
416 |
+
// [workaround(intel)] Separate function required here
|
417 |
+
// [workaround(msvc)] Can't use constexpr bool in return type
|
418 |
+
|
419 |
+
// Add the buffer interface to a vector
|
420 |
+
template <typename Vector, typename Class_, typename... Args>
|
421 |
+
void vector_buffer_impl(Class_ &cl, std::true_type) {
|
422 |
+
using T = typename Vector::value_type;
|
423 |
+
|
424 |
+
static_assert(vector_has_data_and_format<Vector>::value,
|
425 |
+
"There is not an appropriate format descriptor for this vector");
|
426 |
+
|
427 |
+
// numpy.h declares this for arbitrary types, but it may raise an exception and crash hard
|
428 |
+
// at runtime if PYBIND11_NUMPY_DTYPE hasn't been called, so check here
|
429 |
+
format_descriptor<T>::format();
|
430 |
+
|
431 |
+
cl.def_buffer([](Vector &v) -> buffer_info {
|
432 |
+
return buffer_info(v.data(),
|
433 |
+
static_cast<ssize_t>(sizeof(T)),
|
434 |
+
format_descriptor<T>::format(),
|
435 |
+
1,
|
436 |
+
{v.size()},
|
437 |
+
{sizeof(T)});
|
438 |
+
});
|
439 |
+
|
440 |
+
cl.def(init([](const buffer &buf) {
|
441 |
+
auto info = buf.request();
|
442 |
+
if (info.ndim != 1 || info.strides[0] % static_cast<ssize_t>(sizeof(T))) {
|
443 |
+
throw type_error("Only valid 1D buffers can be copied to a vector");
|
444 |
+
}
|
445 |
+
if (!detail::compare_buffer_info<T>::compare(info)
|
446 |
+
|| (ssize_t) sizeof(T) != info.itemsize) {
|
447 |
+
throw type_error("Format mismatch (Python: " + info.format
|
448 |
+
+ " C++: " + format_descriptor<T>::format() + ")");
|
449 |
+
}
|
450 |
+
|
451 |
+
T *p = static_cast<T *>(info.ptr);
|
452 |
+
ssize_t step = info.strides[0] / static_cast<ssize_t>(sizeof(T));
|
453 |
+
T *end = p + info.shape[0] * step;
|
454 |
+
if (step == 1) {
|
455 |
+
return Vector(p, end);
|
456 |
+
}
|
457 |
+
Vector vec;
|
458 |
+
vec.reserve((size_t) info.shape[0]);
|
459 |
+
for (; p != end; p += step) {
|
460 |
+
vec.push_back(*p);
|
461 |
+
}
|
462 |
+
return vec;
|
463 |
+
}));
|
464 |
+
|
465 |
+
return;
|
466 |
+
}
|
467 |
+
|
468 |
+
template <typename Vector, typename Class_, typename... Args>
|
469 |
+
void vector_buffer_impl(Class_ &, std::false_type) {}
|
470 |
+
|
471 |
+
template <typename Vector, typename Class_, typename... Args>
|
472 |
+
void vector_buffer(Class_ &cl) {
|
473 |
+
vector_buffer_impl<Vector, Class_, Args...>(
|
474 |
+
cl, detail::any_of<std::is_same<Args, buffer_protocol>...>{});
|
475 |
+
}
|
476 |
+
|
477 |
+
PYBIND11_NAMESPACE_END(detail)
|
478 |
+
|
479 |
+
//
|
480 |
+
// std::vector
|
481 |
+
//
|
482 |
+
template <typename Vector, typename holder_type = std::unique_ptr<Vector>, typename... Args>
|
483 |
+
class_<Vector, holder_type> bind_vector(handle scope, std::string const &name, Args &&...args) {
|
484 |
+
using Class_ = class_<Vector, holder_type>;
|
485 |
+
|
486 |
+
// If the value_type is unregistered (e.g. a converting type) or is itself registered
|
487 |
+
// module-local then make the vector binding module-local as well:
|
488 |
+
using vtype = typename Vector::value_type;
|
489 |
+
auto *vtype_info = detail::get_type_info(typeid(vtype));
|
490 |
+
bool local = !vtype_info || vtype_info->module_local;
|
491 |
+
|
492 |
+
Class_ cl(scope, name.c_str(), pybind11::module_local(local), std::forward<Args>(args)...);
|
493 |
+
|
494 |
+
// Declare the buffer interface if a buffer_protocol() is passed in
|
495 |
+
detail::vector_buffer<Vector, Class_, Args...>(cl);
|
496 |
+
|
497 |
+
cl.def(init<>());
|
498 |
+
|
499 |
+
// Register copy constructor (if possible)
|
500 |
+
detail::vector_if_copy_constructible<Vector, Class_>(cl);
|
501 |
+
|
502 |
+
// Register comparison-related operators and functions (if possible)
|
503 |
+
detail::vector_if_equal_operator<Vector, Class_>(cl);
|
504 |
+
|
505 |
+
// Register stream insertion operator (if possible)
|
506 |
+
detail::vector_if_insertion_operator<Vector, Class_>(cl, name);
|
507 |
+
|
508 |
+
// Modifiers require copyable vector value type
|
509 |
+
detail::vector_modifiers<Vector, Class_>(cl);
|
510 |
+
|
511 |
+
// Accessor and iterator; return by value if copyable, otherwise we return by ref + keep-alive
|
512 |
+
detail::vector_accessor<Vector, Class_>(cl);
|
513 |
+
|
514 |
+
cl.def(
|
515 |
+
"__bool__",
|
516 |
+
[](const Vector &v) -> bool { return !v.empty(); },
|
517 |
+
"Check whether the list is nonempty");
|
518 |
+
|
519 |
+
cl.def("__len__", &Vector::size);
|
520 |
+
|
521 |
+
#if 0
|
522 |
+
// C++ style functions deprecated, leaving it here as an example
|
523 |
+
cl.def(init<size_type>());
|
524 |
+
|
525 |
+
cl.def("resize",
|
526 |
+
(void (Vector::*) (size_type count)) & Vector::resize,
|
527 |
+
"changes the number of elements stored");
|
528 |
+
|
529 |
+
cl.def("erase",
|
530 |
+
[](Vector &v, SizeType i) {
|
531 |
+
if (i >= v.size())
|
532 |
+
throw index_error();
|
533 |
+
v.erase(v.begin() + i);
|
534 |
+
}, "erases element at index ``i``");
|
535 |
+
|
536 |
+
cl.def("empty", &Vector::empty, "checks whether the container is empty");
|
537 |
+
cl.def("size", &Vector::size, "returns the number of elements");
|
538 |
+
cl.def("push_back", (void (Vector::*)(const T&)) &Vector::push_back, "adds an element to the end");
|
539 |
+
cl.def("pop_back", &Vector::pop_back, "removes the last element");
|
540 |
+
|
541 |
+
cl.def("max_size", &Vector::max_size, "returns the maximum possible number of elements");
|
542 |
+
cl.def("reserve", &Vector::reserve, "reserves storage");
|
543 |
+
cl.def("capacity", &Vector::capacity, "returns the number of elements that can be held in currently allocated storage");
|
544 |
+
cl.def("shrink_to_fit", &Vector::shrink_to_fit, "reduces memory usage by freeing unused memory");
|
545 |
+
|
546 |
+
cl.def("clear", &Vector::clear, "clears the contents");
|
547 |
+
cl.def("swap", &Vector::swap, "swaps the contents");
|
548 |
+
|
549 |
+
cl.def("front", [](Vector &v) {
|
550 |
+
if (v.size()) return v.front();
|
551 |
+
else throw index_error();
|
552 |
+
}, "access the first element");
|
553 |
+
|
554 |
+
cl.def("back", [](Vector &v) {
|
555 |
+
if (v.size()) return v.back();
|
556 |
+
else throw index_error();
|
557 |
+
}, "access the last element ");
|
558 |
+
|
559 |
+
#endif
|
560 |
+
|
561 |
+
return cl;
|
562 |
+
}
|
563 |
+
|
564 |
+
//
|
565 |
+
// std::map, std::unordered_map
|
566 |
+
//
|
567 |
+
|
568 |
+
PYBIND11_NAMESPACE_BEGIN(detail)
|
569 |
+
|
570 |
+
/* Fallback functions */
|
571 |
+
template <typename, typename, typename... Args>
|
572 |
+
void map_if_insertion_operator(const Args &...) {}
|
573 |
+
template <typename, typename, typename... Args>
|
574 |
+
void map_assignment(const Args &...) {}
|
575 |
+
|
576 |
+
// Map assignment when copy-assignable: just copy the value
|
577 |
+
template <typename Map, typename Class_>
|
578 |
+
void map_assignment(
|
579 |
+
enable_if_t<is_copy_assignable<typename Map::mapped_type>::value, Class_> &cl) {
|
580 |
+
using KeyType = typename Map::key_type;
|
581 |
+
using MappedType = typename Map::mapped_type;
|
582 |
+
|
583 |
+
cl.def("__setitem__", [](Map &m, const KeyType &k, const MappedType &v) {
|
584 |
+
auto it = m.find(k);
|
585 |
+
if (it != m.end()) {
|
586 |
+
it->second = v;
|
587 |
+
} else {
|
588 |
+
m.emplace(k, v);
|
589 |
+
}
|
590 |
+
});
|
591 |
+
}
|
592 |
+
|
593 |
+
// Not copy-assignable, but still copy-constructible: we can update the value by erasing and
|
594 |
+
// reinserting
|
595 |
+
template <typename Map, typename Class_>
|
596 |
+
void map_assignment(enable_if_t<!is_copy_assignable<typename Map::mapped_type>::value
|
597 |
+
&& is_copy_constructible<typename Map::mapped_type>::value,
|
598 |
+
Class_> &cl) {
|
599 |
+
using KeyType = typename Map::key_type;
|
600 |
+
using MappedType = typename Map::mapped_type;
|
601 |
+
|
602 |
+
cl.def("__setitem__", [](Map &m, const KeyType &k, const MappedType &v) {
|
603 |
+
// We can't use m[k] = v; because value type might not be default constructable
|
604 |
+
auto r = m.emplace(k, v);
|
605 |
+
if (!r.second) {
|
606 |
+
// value type is not copy assignable so the only way to insert it is to erase it
|
607 |
+
// first...
|
608 |
+
m.erase(r.first);
|
609 |
+
m.emplace(k, v);
|
610 |
+
}
|
611 |
+
});
|
612 |
+
}
|
613 |
+
|
614 |
+
template <typename Map, typename Class_>
|
615 |
+
auto map_if_insertion_operator(Class_ &cl, std::string const &name)
|
616 |
+
-> decltype(std::declval<std::ostream &>() << std::declval<typename Map::key_type>()
|
617 |
+
<< std::declval<typename Map::mapped_type>(),
|
618 |
+
void()) {
|
619 |
+
|
620 |
+
cl.def(
|
621 |
+
"__repr__",
|
622 |
+
[name](Map &m) {
|
623 |
+
std::ostringstream s;
|
624 |
+
s << name << '{';
|
625 |
+
bool f = false;
|
626 |
+
for (auto const &kv : m) {
|
627 |
+
if (f) {
|
628 |
+
s << ", ";
|
629 |
+
}
|
630 |
+
s << kv.first << ": " << kv.second;
|
631 |
+
f = true;
|
632 |
+
}
|
633 |
+
s << '}';
|
634 |
+
return s.str();
|
635 |
+
},
|
636 |
+
"Return the canonical string representation of this map.");
|
637 |
+
}
|
638 |
+
|
639 |
+
template <typename Map>
|
640 |
+
struct keys_view {
|
641 |
+
Map ↦
|
642 |
+
};
|
643 |
+
|
644 |
+
template <typename Map>
|
645 |
+
struct values_view {
|
646 |
+
Map ↦
|
647 |
+
};
|
648 |
+
|
649 |
+
template <typename Map>
|
650 |
+
struct items_view {
|
651 |
+
Map ↦
|
652 |
+
};
|
653 |
+
|
654 |
+
PYBIND11_NAMESPACE_END(detail)
|
655 |
+
|
656 |
+
template <typename Map, typename holder_type = std::unique_ptr<Map>, typename... Args>
|
657 |
+
class_<Map, holder_type> bind_map(handle scope, const std::string &name, Args &&...args) {
|
658 |
+
using KeyType = typename Map::key_type;
|
659 |
+
using MappedType = typename Map::mapped_type;
|
660 |
+
using KeysView = detail::keys_view<Map>;
|
661 |
+
using ValuesView = detail::values_view<Map>;
|
662 |
+
using ItemsView = detail::items_view<Map>;
|
663 |
+
using Class_ = class_<Map, holder_type>;
|
664 |
+
|
665 |
+
// If either type is a non-module-local bound type then make the map binding non-local as well;
|
666 |
+
// otherwise (e.g. both types are either module-local or converting) the map will be
|
667 |
+
// module-local.
|
668 |
+
auto *tinfo = detail::get_type_info(typeid(MappedType));
|
669 |
+
bool local = !tinfo || tinfo->module_local;
|
670 |
+
if (local) {
|
671 |
+
tinfo = detail::get_type_info(typeid(KeyType));
|
672 |
+
local = !tinfo || tinfo->module_local;
|
673 |
+
}
|
674 |
+
|
675 |
+
Class_ cl(scope, name.c_str(), pybind11::module_local(local), std::forward<Args>(args)...);
|
676 |
+
class_<KeysView> keys_view(
|
677 |
+
scope, ("KeysView[" + name + "]").c_str(), pybind11::module_local(local));
|
678 |
+
class_<ValuesView> values_view(
|
679 |
+
scope, ("ValuesView[" + name + "]").c_str(), pybind11::module_local(local));
|
680 |
+
class_<ItemsView> items_view(
|
681 |
+
scope, ("ItemsView[" + name + "]").c_str(), pybind11::module_local(local));
|
682 |
+
|
683 |
+
cl.def(init<>());
|
684 |
+
|
685 |
+
// Register stream insertion operator (if possible)
|
686 |
+
detail::map_if_insertion_operator<Map, Class_>(cl, name);
|
687 |
+
|
688 |
+
cl.def(
|
689 |
+
"__bool__",
|
690 |
+
[](const Map &m) -> bool { return !m.empty(); },
|
691 |
+
"Check whether the map is nonempty");
|
692 |
+
|
693 |
+
cl.def(
|
694 |
+
"__iter__",
|
695 |
+
[](Map &m) { return make_key_iterator(m.begin(), m.end()); },
|
696 |
+
keep_alive<0, 1>() /* Essential: keep map alive while iterator exists */
|
697 |
+
);
|
698 |
+
|
699 |
+
cl.def(
|
700 |
+
"keys",
|
701 |
+
[](Map &m) { return KeysView{m}; },
|
702 |
+
keep_alive<0, 1>() /* Essential: keep map alive while view exists */
|
703 |
+
);
|
704 |
+
|
705 |
+
cl.def(
|
706 |
+
"values",
|
707 |
+
[](Map &m) { return ValuesView{m}; },
|
708 |
+
keep_alive<0, 1>() /* Essential: keep map alive while view exists */
|
709 |
+
);
|
710 |
+
|
711 |
+
cl.def(
|
712 |
+
"items",
|
713 |
+
[](Map &m) { return ItemsView{m}; },
|
714 |
+
keep_alive<0, 1>() /* Essential: keep map alive while view exists */
|
715 |
+
);
|
716 |
+
|
717 |
+
cl.def(
|
718 |
+
"__getitem__",
|
719 |
+
[](Map &m, const KeyType &k) -> MappedType & {
|
720 |
+
auto it = m.find(k);
|
721 |
+
if (it == m.end()) {
|
722 |
+
throw key_error();
|
723 |
+
}
|
724 |
+
return it->second;
|
725 |
+
},
|
726 |
+
return_value_policy::reference_internal // ref + keepalive
|
727 |
+
);
|
728 |
+
|
729 |
+
cl.def("__contains__", [](Map &m, const KeyType &k) -> bool {
|
730 |
+
auto it = m.find(k);
|
731 |
+
if (it == m.end()) {
|
732 |
+
return false;
|
733 |
+
}
|
734 |
+
return true;
|
735 |
+
});
|
736 |
+
// Fallback for when the object is not of the key type
|
737 |
+
cl.def("__contains__", [](Map &, const object &) -> bool { return false; });
|
738 |
+
|
739 |
+
// Assignment provided only if the type is copyable
|
740 |
+
detail::map_assignment<Map, Class_>(cl);
|
741 |
+
|
742 |
+
cl.def("__delitem__", [](Map &m, const KeyType &k) {
|
743 |
+
auto it = m.find(k);
|
744 |
+
if (it == m.end()) {
|
745 |
+
throw key_error();
|
746 |
+
}
|
747 |
+
m.erase(it);
|
748 |
+
});
|
749 |
+
|
750 |
+
cl.def("__len__", &Map::size);
|
751 |
+
|
752 |
+
keys_view.def("__len__", [](KeysView &view) { return view.map.size(); });
|
753 |
+
keys_view.def(
|
754 |
+
"__iter__",
|
755 |
+
[](KeysView &view) { return make_key_iterator(view.map.begin(), view.map.end()); },
|
756 |
+
keep_alive<0, 1>() /* Essential: keep view alive while iterator exists */
|
757 |
+
);
|
758 |
+
keys_view.def("__contains__", [](KeysView &view, const KeyType &k) -> bool {
|
759 |
+
auto it = view.map.find(k);
|
760 |
+
if (it == view.map.end()) {
|
761 |
+
return false;
|
762 |
+
}
|
763 |
+
return true;
|
764 |
+
});
|
765 |
+
// Fallback for when the object is not of the key type
|
766 |
+
keys_view.def("__contains__", [](KeysView &, const object &) -> bool { return false; });
|
767 |
+
|
768 |
+
values_view.def("__len__", [](ValuesView &view) { return view.map.size(); });
|
769 |
+
values_view.def(
|
770 |
+
"__iter__",
|
771 |
+
[](ValuesView &view) { return make_value_iterator(view.map.begin(), view.map.end()); },
|
772 |
+
keep_alive<0, 1>() /* Essential: keep view alive while iterator exists */
|
773 |
+
);
|
774 |
+
|
775 |
+
items_view.def("__len__", [](ItemsView &view) { return view.map.size(); });
|
776 |
+
items_view.def(
|
777 |
+
"__iter__",
|
778 |
+
[](ItemsView &view) { return make_iterator(view.map.begin(), view.map.end()); },
|
779 |
+
keep_alive<0, 1>() /* Essential: keep view alive while iterator exists */
|
780 |
+
);
|
781 |
+
|
782 |
+
return cl;
|
783 |
+
}
|
784 |
+
|
785 |
+
PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)
|
third-party/DPVO/DPViewer/pybind11/noxfile.py
ADDED
@@ -0,0 +1,97 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import os
|
2 |
+
|
3 |
+
import nox
|
4 |
+
|
5 |
+
nox.needs_version = ">=2022.1.7"
|
6 |
+
nox.options.sessions = ["lint", "tests", "tests_packaging"]
|
7 |
+
|
8 |
+
PYTHON_VERISONS = ["3.6", "3.7", "3.8", "3.9", "3.10", "3.11", "pypy3.7", "pypy3.8"]
|
9 |
+
|
10 |
+
if os.environ.get("CI", None):
|
11 |
+
nox.options.error_on_missing_interpreters = True
|
12 |
+
|
13 |
+
|
14 |
+
@nox.session(reuse_venv=True)
|
15 |
+
def lint(session: nox.Session) -> None:
|
16 |
+
"""
|
17 |
+
Lint the codebase (except for clang-format/tidy).
|
18 |
+
"""
|
19 |
+
session.install("pre-commit")
|
20 |
+
session.run("pre-commit", "run", "-a")
|
21 |
+
|
22 |
+
|
23 |
+
@nox.session(python=PYTHON_VERISONS)
|
24 |
+
def tests(session: nox.Session) -> None:
|
25 |
+
"""
|
26 |
+
Run the tests (requires a compiler).
|
27 |
+
"""
|
28 |
+
tmpdir = session.create_tmp()
|
29 |
+
session.install("cmake")
|
30 |
+
session.install("-r", "tests/requirements.txt")
|
31 |
+
session.run(
|
32 |
+
"cmake",
|
33 |
+
"-S.",
|
34 |
+
f"-B{tmpdir}",
|
35 |
+
"-DPYBIND11_WERROR=ON",
|
36 |
+
"-DDOWNLOAD_CATCH=ON",
|
37 |
+
"-DDOWNLOAD_EIGEN=ON",
|
38 |
+
*session.posargs,
|
39 |
+
)
|
40 |
+
session.run("cmake", "--build", tmpdir)
|
41 |
+
session.run("cmake", "--build", tmpdir, "--config=Release", "--target", "check")
|
42 |
+
|
43 |
+
|
44 |
+
@nox.session
|
45 |
+
def tests_packaging(session: nox.Session) -> None:
|
46 |
+
"""
|
47 |
+
Run the packaging tests.
|
48 |
+
"""
|
49 |
+
|
50 |
+
session.install("-r", "tests/requirements.txt", "--prefer-binary")
|
51 |
+
session.run("pytest", "tests/extra_python_package")
|
52 |
+
|
53 |
+
|
54 |
+
@nox.session(reuse_venv=True)
|
55 |
+
def docs(session: nox.Session) -> None:
|
56 |
+
"""
|
57 |
+
Build the docs. Pass "serve" to serve.
|
58 |
+
"""
|
59 |
+
|
60 |
+
session.install("-r", "docs/requirements.txt")
|
61 |
+
session.chdir("docs")
|
62 |
+
|
63 |
+
if "pdf" in session.posargs:
|
64 |
+
session.run("sphinx-build", "-b", "latexpdf", ".", "_build")
|
65 |
+
return
|
66 |
+
|
67 |
+
session.run("sphinx-build", "-b", "html", ".", "_build")
|
68 |
+
|
69 |
+
if "serve" in session.posargs:
|
70 |
+
session.log("Launching docs at http://localhost:8000/ - use Ctrl-C to quit")
|
71 |
+
session.run("python", "-m", "http.server", "8000", "-d", "_build/html")
|
72 |
+
elif session.posargs:
|
73 |
+
session.error("Unsupported argument to docs")
|
74 |
+
|
75 |
+
|
76 |
+
@nox.session(reuse_venv=True)
|
77 |
+
def make_changelog(session: nox.Session) -> None:
|
78 |
+
"""
|
79 |
+
Inspect the closed issues and make entries for a changelog.
|
80 |
+
"""
|
81 |
+
session.install("ghapi", "rich")
|
82 |
+
session.run("python", "tools/make_changelog.py")
|
83 |
+
|
84 |
+
|
85 |
+
@nox.session(reuse_venv=True)
|
86 |
+
def build(session: nox.Session) -> None:
|
87 |
+
"""
|
88 |
+
Build SDists and wheels.
|
89 |
+
"""
|
90 |
+
|
91 |
+
session.install("build")
|
92 |
+
session.log("Building normal files")
|
93 |
+
session.run("python", "-m", "build", *session.posargs)
|
94 |
+
session.log("Building pybind11-global files (PYBIND11_GLOBAL_SDIST=1)")
|
95 |
+
session.run(
|
96 |
+
"python", "-m", "build", *session.posargs, env={"PYBIND11_GLOBAL_SDIST": "1"}
|
97 |
+
)
|
third-party/DPVO/DPViewer/pybind11/pybind11/__init__.py
ADDED
@@ -0,0 +1,16 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import sys
|
2 |
+
|
3 |
+
if sys.version_info < (3, 6):
|
4 |
+
msg = "pybind11 does not support Python < 3.6. 2.9 was the last release supporting Python 2.7 and 3.5."
|
5 |
+
raise ImportError(msg)
|
6 |
+
|
7 |
+
|
8 |
+
from ._version import __version__, version_info
|
9 |
+
from .commands import get_cmake_dir, get_include
|
10 |
+
|
11 |
+
__all__ = (
|
12 |
+
"version_info",
|
13 |
+
"__version__",
|
14 |
+
"get_include",
|
15 |
+
"get_cmake_dir",
|
16 |
+
)
|
third-party/DPVO/DPViewer/pybind11/pybind11/__main__.py
ADDED
@@ -0,0 +1,49 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# pylint: disable=missing-function-docstring
|
2 |
+
|
3 |
+
import argparse
|
4 |
+
import sys
|
5 |
+
import sysconfig
|
6 |
+
|
7 |
+
from .commands import get_cmake_dir, get_include
|
8 |
+
|
9 |
+
|
10 |
+
def print_includes() -> None:
|
11 |
+
dirs = [
|
12 |
+
sysconfig.get_path("include"),
|
13 |
+
sysconfig.get_path("platinclude"),
|
14 |
+
get_include(),
|
15 |
+
]
|
16 |
+
|
17 |
+
# Make unique but preserve order
|
18 |
+
unique_dirs = []
|
19 |
+
for d in dirs:
|
20 |
+
if d and d not in unique_dirs:
|
21 |
+
unique_dirs.append(d)
|
22 |
+
|
23 |
+
print(" ".join("-I" + d for d in unique_dirs))
|
24 |
+
|
25 |
+
|
26 |
+
def main() -> None:
|
27 |
+
|
28 |
+
parser = argparse.ArgumentParser()
|
29 |
+
parser.add_argument(
|
30 |
+
"--includes",
|
31 |
+
action="store_true",
|
32 |
+
help="Include flags for both pybind11 and Python headers.",
|
33 |
+
)
|
34 |
+
parser.add_argument(
|
35 |
+
"--cmakedir",
|
36 |
+
action="store_true",
|
37 |
+
help="Print the CMake module directory, ideal for setting -Dpybind11_ROOT in CMake.",
|
38 |
+
)
|
39 |
+
args = parser.parse_args()
|
40 |
+
if not sys.argv[1:]:
|
41 |
+
parser.print_help()
|
42 |
+
if args.includes:
|
43 |
+
print_includes()
|
44 |
+
if args.cmakedir:
|
45 |
+
print(get_cmake_dir())
|
46 |
+
|
47 |
+
|
48 |
+
if __name__ == "__main__":
|
49 |
+
main()
|
third-party/DPVO/DPViewer/pybind11/pybind11/_version.py
ADDED
@@ -0,0 +1,12 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from typing import Union
|
2 |
+
|
3 |
+
|
4 |
+
def _to_int(s: str) -> Union[int, str]:
|
5 |
+
try:
|
6 |
+
return int(s)
|
7 |
+
except ValueError:
|
8 |
+
return s
|
9 |
+
|
10 |
+
|
11 |
+
__version__ = "2.10.0.dev1"
|
12 |
+
version_info = tuple(_to_int(s) for s in __version__.split("."))
|
third-party/DPVO/DPViewer/pybind11/pybind11/commands.py
ADDED
@@ -0,0 +1,25 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import os
|
2 |
+
|
3 |
+
DIR = os.path.abspath(os.path.dirname(__file__))
|
4 |
+
|
5 |
+
|
6 |
+
def get_include(user: bool = False) -> str: # pylint: disable=unused-argument
|
7 |
+
"""
|
8 |
+
Return the path to the pybind11 include directory. The historical "user"
|
9 |
+
argument is unused, and may be removed.
|
10 |
+
"""
|
11 |
+
installed_path = os.path.join(DIR, "include")
|
12 |
+
source_path = os.path.join(os.path.dirname(DIR), "include")
|
13 |
+
return installed_path if os.path.exists(installed_path) else source_path
|
14 |
+
|
15 |
+
|
16 |
+
def get_cmake_dir() -> str:
|
17 |
+
"""
|
18 |
+
Return the path to the pybind11 CMake module directory.
|
19 |
+
"""
|
20 |
+
cmake_installed_path = os.path.join(DIR, "share", "cmake", "pybind11")
|
21 |
+
if os.path.exists(cmake_installed_path):
|
22 |
+
return cmake_installed_path
|
23 |
+
|
24 |
+
msg = "pybind11 not installed, installation required to access the CMake files"
|
25 |
+
raise ImportError(msg)
|
third-party/DPVO/DPViewer/pybind11/pybind11/py.typed
ADDED
File without changes
|
third-party/DPVO/DPViewer/pybind11/pybind11/setup_helpers.py
ADDED
@@ -0,0 +1,504 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
"""
|
2 |
+
This module provides helpers for C++11+ projects using pybind11.
|
3 |
+
|
4 |
+
LICENSE:
|
5 |
+
|
6 |
+
Copyright (c) 2016 Wenzel Jakob <[email protected]>, All rights reserved.
|
7 |
+
|
8 |
+
Redistribution and use in source and binary forms, with or without
|
9 |
+
modification, are permitted provided that the following conditions are met:
|
10 |
+
|
11 |
+
1. Redistributions of source code must retain the above copyright notice, this
|
12 |
+
list of conditions and the following disclaimer.
|
13 |
+
|
14 |
+
2. Redistributions in binary form must reproduce the above copyright notice,
|
15 |
+
this list of conditions and the following disclaimer in the documentation
|
16 |
+
and/or other materials provided with the distribution.
|
17 |
+
|
18 |
+
3. Neither the name of the copyright holder nor the names of its contributors
|
19 |
+
may be used to endorse or promote products derived from this software
|
20 |
+
without specific prior written permission.
|
21 |
+
|
22 |
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
23 |
+
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
24 |
+
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
25 |
+
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
26 |
+
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
27 |
+
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
28 |
+
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
29 |
+
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
30 |
+
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
31 |
+
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
32 |
+
"""
|
33 |
+
|
34 |
+
# IMPORTANT: If you change this file in the pybind11 repo, also review
|
35 |
+
# setup_helpers.pyi for matching changes.
|
36 |
+
#
|
37 |
+
# If you copy this file in, you don't
|
38 |
+
# need the .pyi file; it's just an interface file for static type checkers.
|
39 |
+
|
40 |
+
import contextlib
|
41 |
+
import os
|
42 |
+
import platform
|
43 |
+
import shlex
|
44 |
+
import shutil
|
45 |
+
import sys
|
46 |
+
import sysconfig
|
47 |
+
import tempfile
|
48 |
+
import threading
|
49 |
+
import warnings
|
50 |
+
from functools import lru_cache
|
51 |
+
from pathlib import Path
|
52 |
+
from typing import (
|
53 |
+
Any,
|
54 |
+
Callable,
|
55 |
+
Dict,
|
56 |
+
Iterable,
|
57 |
+
Iterator,
|
58 |
+
List,
|
59 |
+
Optional,
|
60 |
+
Tuple,
|
61 |
+
TypeVar,
|
62 |
+
Union,
|
63 |
+
)
|
64 |
+
|
65 |
+
try:
|
66 |
+
from setuptools import Extension as _Extension
|
67 |
+
from setuptools.command.build_ext import build_ext as _build_ext
|
68 |
+
except ImportError:
|
69 |
+
from distutils.command.build_ext import build_ext as _build_ext
|
70 |
+
from distutils.extension import Extension as _Extension
|
71 |
+
|
72 |
+
import distutils.ccompiler
|
73 |
+
import distutils.errors
|
74 |
+
|
75 |
+
WIN = sys.platform.startswith("win32") and "mingw" not in sysconfig.get_platform()
|
76 |
+
MACOS = sys.platform.startswith("darwin")
|
77 |
+
STD_TMPL = "/std:c++{}" if WIN else "-std=c++{}"
|
78 |
+
|
79 |
+
|
80 |
+
# It is recommended to use PEP 518 builds if using this module. However, this
|
81 |
+
# file explicitly supports being copied into a user's project directory
|
82 |
+
# standalone, and pulling pybind11 with the deprecated setup_requires feature.
|
83 |
+
# If you copy the file, remember to add it to your MANIFEST.in, and add the current
|
84 |
+
# directory into your path if it sits beside your setup.py.
|
85 |
+
|
86 |
+
|
87 |
+
class Pybind11Extension(_Extension): # type: ignore[misc]
|
88 |
+
"""
|
89 |
+
Build a C++11+ Extension module with pybind11. This automatically adds the
|
90 |
+
recommended flags when you init the extension and assumes C++ sources - you
|
91 |
+
can further modify the options yourself.
|
92 |
+
|
93 |
+
The customizations are:
|
94 |
+
|
95 |
+
* ``/EHsc`` and ``/bigobj`` on Windows
|
96 |
+
* ``stdlib=libc++`` on macOS
|
97 |
+
* ``visibility=hidden`` and ``-g0`` on Unix
|
98 |
+
|
99 |
+
Finally, you can set ``cxx_std`` via constructor or afterwards to enable
|
100 |
+
flags for C++ std, and a few extra helper flags related to the C++ standard
|
101 |
+
level. It is _highly_ recommended you either set this, or use the provided
|
102 |
+
``build_ext``, which will search for the highest supported extension for
|
103 |
+
you if the ``cxx_std`` property is not set. Do not set the ``cxx_std``
|
104 |
+
property more than once, as flags are added when you set it. Set the
|
105 |
+
property to None to disable the addition of C++ standard flags.
|
106 |
+
|
107 |
+
If you want to add pybind11 headers manually, for example for an exact
|
108 |
+
git checkout, then set ``include_pybind11=False``.
|
109 |
+
"""
|
110 |
+
|
111 |
+
# flags are prepended, so that they can be further overridden, e.g. by
|
112 |
+
# ``extra_compile_args=["-g"]``.
|
113 |
+
|
114 |
+
def _add_cflags(self, flags: List[str]) -> None:
|
115 |
+
self.extra_compile_args[:0] = flags
|
116 |
+
|
117 |
+
def _add_ldflags(self, flags: List[str]) -> None:
|
118 |
+
self.extra_link_args[:0] = flags
|
119 |
+
|
120 |
+
def __init__(self, *args: Any, **kwargs: Any) -> None:
|
121 |
+
|
122 |
+
self._cxx_level = 0
|
123 |
+
cxx_std = kwargs.pop("cxx_std", 0)
|
124 |
+
|
125 |
+
if "language" not in kwargs:
|
126 |
+
kwargs["language"] = "c++"
|
127 |
+
|
128 |
+
include_pybind11 = kwargs.pop("include_pybind11", True)
|
129 |
+
|
130 |
+
super().__init__(*args, **kwargs)
|
131 |
+
|
132 |
+
# Include the installed package pybind11 headers
|
133 |
+
if include_pybind11:
|
134 |
+
# If using setup_requires, this fails the first time - that's okay
|
135 |
+
try:
|
136 |
+
import pybind11
|
137 |
+
|
138 |
+
pyinc = pybind11.get_include()
|
139 |
+
|
140 |
+
if pyinc not in self.include_dirs:
|
141 |
+
self.include_dirs.append(pyinc)
|
142 |
+
except ModuleNotFoundError:
|
143 |
+
pass
|
144 |
+
|
145 |
+
self.cxx_std = cxx_std
|
146 |
+
|
147 |
+
cflags = []
|
148 |
+
ldflags = []
|
149 |
+
if WIN:
|
150 |
+
cflags += ["/EHsc", "/bigobj"]
|
151 |
+
else:
|
152 |
+
cflags += ["-fvisibility=hidden"]
|
153 |
+
env_cflags = os.environ.get("CFLAGS", "")
|
154 |
+
env_cppflags = os.environ.get("CPPFLAGS", "")
|
155 |
+
c_cpp_flags = shlex.split(env_cflags) + shlex.split(env_cppflags)
|
156 |
+
if not any(opt.startswith("-g") for opt in c_cpp_flags):
|
157 |
+
cflags += ["-g0"]
|
158 |
+
if MACOS:
|
159 |
+
cflags += ["-stdlib=libc++"]
|
160 |
+
ldflags += ["-stdlib=libc++"]
|
161 |
+
self._add_cflags(cflags)
|
162 |
+
self._add_ldflags(ldflags)
|
163 |
+
|
164 |
+
@property
|
165 |
+
def cxx_std(self) -> int:
|
166 |
+
"""
|
167 |
+
The CXX standard level. If set, will add the required flags. If left at
|
168 |
+
0, it will trigger an automatic search when pybind11's build_ext is
|
169 |
+
used. If None, will have no effect. Besides just the flags, this may
|
170 |
+
add a macos-min 10.9 or 10.14 flag if MACOSX_DEPLOYMENT_TARGET is
|
171 |
+
unset.
|
172 |
+
"""
|
173 |
+
return self._cxx_level
|
174 |
+
|
175 |
+
@cxx_std.setter
|
176 |
+
def cxx_std(self, level: int) -> None:
|
177 |
+
|
178 |
+
if self._cxx_level:
|
179 |
+
warnings.warn("You cannot safely change the cxx_level after setting it!")
|
180 |
+
|
181 |
+
# MSVC 2015 Update 3 and later only have 14 (and later 17) modes, so
|
182 |
+
# force a valid flag here.
|
183 |
+
if WIN and level == 11:
|
184 |
+
level = 14
|
185 |
+
|
186 |
+
self._cxx_level = level
|
187 |
+
|
188 |
+
if not level:
|
189 |
+
return
|
190 |
+
|
191 |
+
cflags = [STD_TMPL.format(level)]
|
192 |
+
ldflags = []
|
193 |
+
|
194 |
+
if MACOS and "MACOSX_DEPLOYMENT_TARGET" not in os.environ:
|
195 |
+
# C++17 requires a higher min version of macOS. An earlier version
|
196 |
+
# (10.12 or 10.13) can be set manually via environment variable if
|
197 |
+
# you are careful in your feature usage, but 10.14 is the safest
|
198 |
+
# setting for general use. However, never set higher than the
|
199 |
+
# current macOS version!
|
200 |
+
current_macos = tuple(int(x) for x in platform.mac_ver()[0].split(".")[:2])
|
201 |
+
desired_macos = (10, 9) if level < 17 else (10, 14)
|
202 |
+
macos_string = ".".join(str(x) for x in min(current_macos, desired_macos))
|
203 |
+
macosx_min = f"-mmacosx-version-min={macos_string}"
|
204 |
+
cflags += [macosx_min]
|
205 |
+
ldflags += [macosx_min]
|
206 |
+
|
207 |
+
self._add_cflags(cflags)
|
208 |
+
self._add_ldflags(ldflags)
|
209 |
+
|
210 |
+
|
211 |
+
# Just in case someone clever tries to multithread
|
212 |
+
tmp_chdir_lock = threading.Lock()
|
213 |
+
|
214 |
+
|
215 |
+
@contextlib.contextmanager
|
216 |
+
def tmp_chdir() -> Iterator[str]:
|
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: Any, flag: str) -> bool:
|
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 = Path("flagcheck.cpp")
|
241 |
+
# Don't trigger -Wunused-parameter.
|
242 |
+
fname.write_text("int main (int, char **) { return 0; }", encoding="utf-8")
|
243 |
+
|
244 |
+
try:
|
245 |
+
compiler.compile([str(fname)], extra_postargs=[flag])
|
246 |
+
except distutils.errors.CompileError:
|
247 |
+
return False
|
248 |
+
return True
|
249 |
+
|
250 |
+
|
251 |
+
# Every call will cache the result
|
252 |
+
cpp_flag_cache = None
|
253 |
+
|
254 |
+
|
255 |
+
@lru_cache()
|
256 |
+
def auto_cpp_level(compiler: Any) -> Union[str, int]:
|
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 |
+
levels = [17, 14, 11]
|
265 |
+
|
266 |
+
for level in levels:
|
267 |
+
if has_flag(compiler, STD_TMPL.format(level)):
|
268 |
+
return level
|
269 |
+
|
270 |
+
msg = "Unsupported compiler -- at least C++11 support is needed!"
|
271 |
+
raise RuntimeError(msg)
|
272 |
+
|
273 |
+
|
274 |
+
class build_ext(_build_ext): # type: ignore[misc] # noqa: N801
|
275 |
+
"""
|
276 |
+
Customized build_ext that allows an auto-search for the highest supported
|
277 |
+
C++ level for Pybind11Extension. This is only needed for the auto-search
|
278 |
+
for now, and is completely optional otherwise.
|
279 |
+
"""
|
280 |
+
|
281 |
+
def build_extensions(self) -> None:
|
282 |
+
"""
|
283 |
+
Build extensions, injecting C++ std for Pybind11Extension if needed.
|
284 |
+
"""
|
285 |
+
|
286 |
+
for ext in self.extensions:
|
287 |
+
if hasattr(ext, "_cxx_level") and ext._cxx_level == 0:
|
288 |
+
ext.cxx_std = auto_cpp_level(self.compiler)
|
289 |
+
|
290 |
+
super().build_extensions()
|
291 |
+
|
292 |
+
|
293 |
+
def intree_extensions(
|
294 |
+
paths: Iterable[str], package_dir: Optional[Dict[str, str]] = None
|
295 |
+
) -> List[Pybind11Extension]:
|
296 |
+
"""
|
297 |
+
Generate Pybind11Extensions from source files directly located in a Python
|
298 |
+
source tree.
|
299 |
+
|
300 |
+
``package_dir`` behaves as in ``setuptools.setup``. If unset, the Python
|
301 |
+
package root parent is determined as the first parent directory that does
|
302 |
+
not contain an ``__init__.py`` file.
|
303 |
+
"""
|
304 |
+
exts = []
|
305 |
+
|
306 |
+
if package_dir is None:
|
307 |
+
for path in paths:
|
308 |
+
parent, _ = os.path.split(path)
|
309 |
+
while os.path.exists(os.path.join(parent, "__init__.py")):
|
310 |
+
parent, _ = os.path.split(parent)
|
311 |
+
relname, _ = os.path.splitext(os.path.relpath(path, parent))
|
312 |
+
qualified_name = relname.replace(os.path.sep, ".")
|
313 |
+
exts.append(Pybind11Extension(qualified_name, [path]))
|
314 |
+
return exts
|
315 |
+
|
316 |
+
for path in paths:
|
317 |
+
for prefix, parent in package_dir.items():
|
318 |
+
if path.startswith(parent):
|
319 |
+
relname, _ = os.path.splitext(os.path.relpath(path, parent))
|
320 |
+
qualified_name = relname.replace(os.path.sep, ".")
|
321 |
+
if prefix:
|
322 |
+
qualified_name = prefix + "." + qualified_name
|
323 |
+
exts.append(Pybind11Extension(qualified_name, [path]))
|
324 |
+
break
|
325 |
+
else:
|
326 |
+
msg = (
|
327 |
+
f"path {path} is not a child of any of the directories listed "
|
328 |
+
f"in 'package_dir' ({package_dir})"
|
329 |
+
)
|
330 |
+
raise ValueError(msg)
|
331 |
+
|
332 |
+
return exts
|
333 |
+
|
334 |
+
|
335 |
+
def naive_recompile(obj: str, src: str) -> bool:
|
336 |
+
"""
|
337 |
+
This will recompile only if the source file changes. It does not check
|
338 |
+
header files, so a more advanced function or Ccache is better if you have
|
339 |
+
editable header files in your package.
|
340 |
+
"""
|
341 |
+
return os.stat(obj).st_mtime < os.stat(src).st_mtime
|
342 |
+
|
343 |
+
|
344 |
+
def no_recompile(obg: str, src: str) -> bool: # pylint: disable=unused-argument
|
345 |
+
"""
|
346 |
+
This is the safest but slowest choice (and is the default) - will always
|
347 |
+
recompile sources.
|
348 |
+
"""
|
349 |
+
return True
|
350 |
+
|
351 |
+
|
352 |
+
S = TypeVar("S", bound="ParallelCompile")
|
353 |
+
|
354 |
+
CCompilerMethod = Callable[
|
355 |
+
[
|
356 |
+
distutils.ccompiler.CCompiler,
|
357 |
+
List[str],
|
358 |
+
Optional[str],
|
359 |
+
Optional[Union[Tuple[str], Tuple[str, Optional[str]]]],
|
360 |
+
Optional[List[str]],
|
361 |
+
bool,
|
362 |
+
Optional[List[str]],
|
363 |
+
Optional[List[str]],
|
364 |
+
Optional[List[str]],
|
365 |
+
],
|
366 |
+
List[str],
|
367 |
+
]
|
368 |
+
|
369 |
+
|
370 |
+
# Optional parallel compile utility
|
371 |
+
# inspired by: http://stackoverflow.com/questions/11013851/speeding-up-build-process-with-distutils
|
372 |
+
# and: https://github.com/tbenthompson/cppimport/blob/stable/cppimport/build_module.py
|
373 |
+
# and NumPy's parallel distutils module:
|
374 |
+
# https://github.com/numpy/numpy/blob/master/numpy/distutils/ccompiler.py
|
375 |
+
class ParallelCompile:
|
376 |
+
"""
|
377 |
+
Make a parallel compile function. Inspired by
|
378 |
+
numpy.distutils.ccompiler.CCompiler.compile and cppimport.
|
379 |
+
|
380 |
+
This takes several arguments that allow you to customize the compile
|
381 |
+
function created:
|
382 |
+
|
383 |
+
envvar:
|
384 |
+
Set an environment variable to control the compilation threads, like
|
385 |
+
NPY_NUM_BUILD_JOBS
|
386 |
+
default:
|
387 |
+
0 will automatically multithread, or 1 will only multithread if the
|
388 |
+
envvar is set.
|
389 |
+
max:
|
390 |
+
The limit for automatic multithreading if non-zero
|
391 |
+
needs_recompile:
|
392 |
+
A function of (obj, src) that returns True when recompile is needed. No
|
393 |
+
effect in isolated mode; use ccache instead, see
|
394 |
+
https://github.com/matplotlib/matplotlib/issues/1507/
|
395 |
+
|
396 |
+
To use::
|
397 |
+
|
398 |
+
ParallelCompile("NPY_NUM_BUILD_JOBS").install()
|
399 |
+
|
400 |
+
or::
|
401 |
+
|
402 |
+
with ParallelCompile("NPY_NUM_BUILD_JOBS"):
|
403 |
+
setup(...)
|
404 |
+
|
405 |
+
By default, this assumes all files need to be recompiled. A smarter
|
406 |
+
function can be provided via needs_recompile. If the output has not yet
|
407 |
+
been generated, the compile will always run, and this function is not
|
408 |
+
called.
|
409 |
+
"""
|
410 |
+
|
411 |
+
__slots__ = ("envvar", "default", "max", "_old", "needs_recompile")
|
412 |
+
|
413 |
+
def __init__(
|
414 |
+
self,
|
415 |
+
envvar: Optional[str] = None,
|
416 |
+
default: int = 0,
|
417 |
+
max: int = 0, # pylint: disable=redefined-builtin
|
418 |
+
needs_recompile: Callable[[str, str], bool] = no_recompile,
|
419 |
+
) -> None:
|
420 |
+
self.envvar = envvar
|
421 |
+
self.default = default
|
422 |
+
self.max = max
|
423 |
+
self.needs_recompile = needs_recompile
|
424 |
+
self._old: List[CCompilerMethod] = []
|
425 |
+
|
426 |
+
def function(self) -> CCompilerMethod:
|
427 |
+
"""
|
428 |
+
Builds a function object usable as distutils.ccompiler.CCompiler.compile.
|
429 |
+
"""
|
430 |
+
|
431 |
+
def compile_function(
|
432 |
+
compiler: distutils.ccompiler.CCompiler,
|
433 |
+
sources: List[str],
|
434 |
+
output_dir: Optional[str] = None,
|
435 |
+
macros: Optional[Union[Tuple[str], Tuple[str, Optional[str]]]] = None,
|
436 |
+
include_dirs: Optional[List[str]] = None,
|
437 |
+
debug: bool = False,
|
438 |
+
extra_preargs: Optional[List[str]] = None,
|
439 |
+
extra_postargs: Optional[List[str]] = None,
|
440 |
+
depends: Optional[List[str]] = None,
|
441 |
+
) -> Any:
|
442 |
+
|
443 |
+
# These lines are directly from distutils.ccompiler.CCompiler
|
444 |
+
macros, objects, extra_postargs, pp_opts, build = compiler._setup_compile( # type: ignore[attr-defined]
|
445 |
+
output_dir, macros, include_dirs, sources, depends, extra_postargs
|
446 |
+
)
|
447 |
+
cc_args = compiler._get_cc_args(pp_opts, debug, extra_preargs) # type: ignore[attr-defined]
|
448 |
+
|
449 |
+
# The number of threads; start with default.
|
450 |
+
threads = self.default
|
451 |
+
|
452 |
+
# Determine the number of compilation threads, unless set by an environment variable.
|
453 |
+
if self.envvar is not None:
|
454 |
+
threads = int(os.environ.get(self.envvar, self.default))
|
455 |
+
|
456 |
+
def _single_compile(obj: Any) -> None:
|
457 |
+
try:
|
458 |
+
src, ext = build[obj]
|
459 |
+
except KeyError:
|
460 |
+
return
|
461 |
+
|
462 |
+
if not os.path.exists(obj) or self.needs_recompile(obj, src):
|
463 |
+
compiler._compile(obj, src, ext, cc_args, extra_postargs, pp_opts) # type: ignore[attr-defined]
|
464 |
+
|
465 |
+
try:
|
466 |
+
# Importing .synchronize checks for platforms that have some multiprocessing
|
467 |
+
# capabilities but lack semaphores, such as AWS Lambda and Android Termux.
|
468 |
+
import multiprocessing.synchronize
|
469 |
+
from multiprocessing.pool import ThreadPool
|
470 |
+
except ImportError:
|
471 |
+
threads = 1
|
472 |
+
|
473 |
+
if threads == 0:
|
474 |
+
try:
|
475 |
+
threads = multiprocessing.cpu_count()
|
476 |
+
threads = self.max if self.max and self.max < threads else threads
|
477 |
+
except NotImplementedError:
|
478 |
+
threads = 1
|
479 |
+
|
480 |
+
if threads > 1:
|
481 |
+
with ThreadPool(threads) as pool:
|
482 |
+
for _ in pool.imap_unordered(_single_compile, objects):
|
483 |
+
pass
|
484 |
+
else:
|
485 |
+
for ob in objects:
|
486 |
+
_single_compile(ob)
|
487 |
+
|
488 |
+
return objects
|
489 |
+
|
490 |
+
return compile_function
|
491 |
+
|
492 |
+
def install(self: S) -> S:
|
493 |
+
"""
|
494 |
+
Installs the compile function into distutils.ccompiler.CCompiler.compile.
|
495 |
+
"""
|
496 |
+
distutils.ccompiler.CCompiler.compile = self.function() # type: ignore[assignment]
|
497 |
+
return self
|
498 |
+
|
499 |
+
def __enter__(self: S) -> S:
|
500 |
+
self._old.append(distutils.ccompiler.CCompiler.compile)
|
501 |
+
return self.install()
|
502 |
+
|
503 |
+
def __exit__(self, *args: Any) -> None:
|
504 |
+
distutils.ccompiler.CCompiler.compile = self._old.pop() # type: ignore[assignment]
|
third-party/DPVO/DPViewer/pybind11/pyproject.toml
ADDED
@@ -0,0 +1,61 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
[build-system]
|
2 |
+
requires = ["setuptools>=42", "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.isort]
|
19 |
+
# Needs the compiled .so modules and env.py from tests
|
20 |
+
known_first_party = "env,pybind11_cross_module_tests,pybind11_tests,"
|
21 |
+
# For black compatibility
|
22 |
+
profile = "black"
|
23 |
+
|
24 |
+
[tool.mypy]
|
25 |
+
files = ["pybind11"]
|
26 |
+
python_version = "3.6"
|
27 |
+
strict = true
|
28 |
+
show_error_codes = true
|
29 |
+
enable_error_code = ["ignore-without-code", "redundant-expr", "truthy-bool"]
|
30 |
+
warn_unreachable = true
|
31 |
+
|
32 |
+
[[tool.mypy.overrides]]
|
33 |
+
module = ["ghapi.*", "setuptools.*"]
|
34 |
+
ignore_missing_imports = true
|
35 |
+
|
36 |
+
|
37 |
+
[tool.pytest.ini_options]
|
38 |
+
minversion = "6.0"
|
39 |
+
addopts = ["-ra", "--showlocals", "--strict-markers", "--strict-config"]
|
40 |
+
xfail_strict = true
|
41 |
+
filterwarnings = ["error"]
|
42 |
+
log_cli_level = "info"
|
43 |
+
testpaths = [
|
44 |
+
"tests",
|
45 |
+
]
|
46 |
+
timeout=300
|
47 |
+
|
48 |
+
|
49 |
+
[tool.pylint]
|
50 |
+
master.py-version = "3.6"
|
51 |
+
reports.output-format = "colorized"
|
52 |
+
messages_control.disable = [
|
53 |
+
"design",
|
54 |
+
"fixme",
|
55 |
+
"imports",
|
56 |
+
"line-too-long",
|
57 |
+
"imports",
|
58 |
+
"invalid-name",
|
59 |
+
"protected-access",
|
60 |
+
"missing-module-docstring",
|
61 |
+
]
|
third-party/DPVO/DPViewer/pybind11/setup.cfg
ADDED
@@ -0,0 +1,49 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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 :: 3 :: Only
|
17 |
+
Programming Language :: Python :: 3.6
|
18 |
+
Programming Language :: Python :: 3.7
|
19 |
+
Programming Language :: Python :: 3.8
|
20 |
+
Programming Language :: Python :: 3.9
|
21 |
+
Programming Language :: Python :: 3.10
|
22 |
+
License :: OSI Approved :: BSD License
|
23 |
+
Programming Language :: Python :: Implementation :: PyPy
|
24 |
+
Programming Language :: Python :: Implementation :: CPython
|
25 |
+
Programming Language :: C++
|
26 |
+
Topic :: Software Development :: Libraries :: Python Modules
|
27 |
+
|
28 |
+
keywords =
|
29 |
+
C++11
|
30 |
+
Python bindings
|
31 |
+
|
32 |
+
project_urls =
|
33 |
+
Documentation = https://pybind11.readthedocs.io/
|
34 |
+
Bug Tracker = https://github.com/pybind/pybind11/issues
|
35 |
+
Discussions = https://github.com/pybind/pybind11/discussions
|
36 |
+
Changelog = https://pybind11.readthedocs.io/en/latest/changelog.html
|
37 |
+
Chat = https://gitter.im/pybind/Lobby
|
38 |
+
|
39 |
+
[options]
|
40 |
+
python_requires = >=3.6
|
41 |
+
zip_safe = False
|
42 |
+
|
43 |
+
|
44 |
+
[flake8]
|
45 |
+
max-line-length = 120
|
46 |
+
show_source = True
|
47 |
+
exclude = .git, __pycache__, build, dist, docs, tools, venv
|
48 |
+
extend-ignore = E203, E722, B950
|
49 |
+
extend-select = B9
|
third-party/DPVO/DPViewer/pybind11/setup.py
ADDED
@@ -0,0 +1,149 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
#!/usr/bin/env python3
|
2 |
+
|
3 |
+
# Setup script for PyPI; use CMakeFile.txt to build extension modules
|
4 |
+
|
5 |
+
import contextlib
|
6 |
+
import os
|
7 |
+
import re
|
8 |
+
import shutil
|
9 |
+
import string
|
10 |
+
import subprocess
|
11 |
+
import sys
|
12 |
+
from pathlib import Path
|
13 |
+
from tempfile import TemporaryDirectory
|
14 |
+
from typing import Dict, Iterator, List, Union
|
15 |
+
|
16 |
+
import setuptools.command.sdist
|
17 |
+
|
18 |
+
DIR = Path(__file__).parent.absolute()
|
19 |
+
VERSION_REGEX = re.compile(
|
20 |
+
r"^\s*#\s*define\s+PYBIND11_VERSION_([A-Z]+)\s+(.*)$", re.MULTILINE
|
21 |
+
)
|
22 |
+
VERSION_FILE = Path("pybind11/_version.py")
|
23 |
+
COMMON_FILE = Path("include/pybind11/detail/common.h")
|
24 |
+
|
25 |
+
|
26 |
+
def build_expected_version_hex(matches: Dict[str, str]) -> str:
|
27 |
+
patch_level_serial = matches["PATCH"]
|
28 |
+
serial = None
|
29 |
+
major = int(matches["MAJOR"])
|
30 |
+
minor = int(matches["MINOR"])
|
31 |
+
flds = patch_level_serial.split(".")
|
32 |
+
if flds:
|
33 |
+
patch = int(flds[0])
|
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 |
+
if serial is None:
|
44 |
+
msg = f'Invalid PYBIND11_VERSION_PATCH: "{patch_level_serial}"'
|
45 |
+
raise RuntimeError(msg)
|
46 |
+
version_hex_str = f"{major:02x}{minor:02x}{patch:02x}{level[:1]}{serial:x}"
|
47 |
+
return f"0x{version_hex_str.upper()}"
|
48 |
+
|
49 |
+
|
50 |
+
# PYBIND11_GLOBAL_SDIST will build a different sdist, with the python-headers
|
51 |
+
# files, and the sys.prefix files (CMake and headers).
|
52 |
+
|
53 |
+
global_sdist = os.environ.get("PYBIND11_GLOBAL_SDIST", False)
|
54 |
+
|
55 |
+
setup_py = Path(
|
56 |
+
"tools/setup_global.py.in" if global_sdist else "tools/setup_main.py.in"
|
57 |
+
)
|
58 |
+
extra_cmd = 'cmdclass["sdist"] = SDist\n'
|
59 |
+
|
60 |
+
to_src = (
|
61 |
+
(Path("pyproject.toml"), Path("tools/pyproject.toml")),
|
62 |
+
(Path("setup.py"), setup_py),
|
63 |
+
)
|
64 |
+
|
65 |
+
|
66 |
+
# Read the listed version
|
67 |
+
loc: Dict[str, str] = {}
|
68 |
+
code = compile(VERSION_FILE.read_text(encoding="utf-8"), "pybind11/_version.py", "exec")
|
69 |
+
exec(code, loc)
|
70 |
+
version = loc["__version__"]
|
71 |
+
|
72 |
+
# Verify that the version matches the one in C++
|
73 |
+
matches = dict(VERSION_REGEX.findall(COMMON_FILE.read_text(encoding="utf8")))
|
74 |
+
cpp_version = "{MAJOR}.{MINOR}.{PATCH}".format(**matches)
|
75 |
+
if version != cpp_version:
|
76 |
+
msg = f"Python version {version} does not match C++ version {cpp_version}!"
|
77 |
+
raise RuntimeError(msg)
|
78 |
+
|
79 |
+
version_hex = matches.get("HEX", "MISSING")
|
80 |
+
exp_version_hex = build_expected_version_hex(matches)
|
81 |
+
if version_hex != exp_version_hex:
|
82 |
+
msg = f"PYBIND11_VERSION_HEX {version_hex} does not match expected value {exp_version_hex}!"
|
83 |
+
raise RuntimeError(msg)
|
84 |
+
|
85 |
+
|
86 |
+
# TODO: use literals & overload (typing extensions or Python 3.8)
|
87 |
+
def get_and_replace(
|
88 |
+
filename: Path, binary: bool = False, **opts: str
|
89 |
+
) -> Union[bytes, str]:
|
90 |
+
if binary:
|
91 |
+
contents = filename.read_bytes()
|
92 |
+
return string.Template(contents.decode()).substitute(opts).encode()
|
93 |
+
|
94 |
+
return string.Template(filename.read_text()).substitute(opts)
|
95 |
+
|
96 |
+
|
97 |
+
# Use our input files instead when making the SDist (and anything that depends
|
98 |
+
# on it, like a wheel)
|
99 |
+
class SDist(setuptools.command.sdist.sdist): # type: ignore[misc]
|
100 |
+
def make_release_tree(self, base_dir: str, files: List[str]) -> None:
|
101 |
+
super().make_release_tree(base_dir, files)
|
102 |
+
|
103 |
+
for to, src in to_src:
|
104 |
+
txt = get_and_replace(src, binary=True, version=version, extra_cmd="")
|
105 |
+
|
106 |
+
dest = Path(base_dir) / to
|
107 |
+
|
108 |
+
# This is normally linked, so unlink before writing!
|
109 |
+
dest.unlink()
|
110 |
+
dest.write_bytes(txt) # type: ignore[arg-type]
|
111 |
+
|
112 |
+
|
113 |
+
# Remove the CMake install directory when done
|
114 |
+
@contextlib.contextmanager
|
115 |
+
def remove_output(*sources: str) -> Iterator[None]:
|
116 |
+
try:
|
117 |
+
yield
|
118 |
+
finally:
|
119 |
+
for src in sources:
|
120 |
+
shutil.rmtree(src)
|
121 |
+
|
122 |
+
|
123 |
+
with remove_output("pybind11/include", "pybind11/share"):
|
124 |
+
# Generate the files if they are not present.
|
125 |
+
with TemporaryDirectory() as tmpdir:
|
126 |
+
cmd = ["cmake", "-S", ".", "-B", tmpdir] + [
|
127 |
+
"-DCMAKE_INSTALL_PREFIX=pybind11",
|
128 |
+
"-DBUILD_TESTING=OFF",
|
129 |
+
"-DPYBIND11_NOPYTHON=ON",
|
130 |
+
]
|
131 |
+
if "CMAKE_ARGS" in os.environ:
|
132 |
+
fcommand = [
|
133 |
+
c
|
134 |
+
for c in os.environ["CMAKE_ARGS"].split()
|
135 |
+
if "DCMAKE_INSTALL_PREFIX" not in c
|
136 |
+
]
|
137 |
+
cmd += fcommand
|
138 |
+
subprocess.run(cmd, check=True, cwd=DIR, stdout=sys.stdout, stderr=sys.stderr)
|
139 |
+
subprocess.run(
|
140 |
+
["cmake", "--install", tmpdir],
|
141 |
+
check=True,
|
142 |
+
cwd=DIR,
|
143 |
+
stdout=sys.stdout,
|
144 |
+
stderr=sys.stderr,
|
145 |
+
)
|
146 |
+
|
147 |
+
txt = get_and_replace(setup_py, version=version, extra_cmd=extra_cmd)
|
148 |
+
code = compile(txt, setup_py, "exec")
|
149 |
+
exec(code, {"SDist": SDist})
|
third-party/DPVO/DPViewer/pybind11/tools/FindCatch.cmake
ADDED
@@ -0,0 +1,72 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# - Find the Catch test framework or download it (single header)
|
2 |
+
#
|
3 |
+
# This is a quick module for internal use. It assumes that Catch is
|
4 |
+
# REQUIRED and that a minimum version is provided (not EXACT). If
|
5 |
+
# a suitable version isn't found locally, the single header file
|
6 |
+
# will be downloaded and placed in the build dir: PROJECT_BINARY_DIR.
|
7 |
+
#
|
8 |
+
# This code sets the following variables:
|
9 |
+
# CATCH_INCLUDE_DIR - path to catch.hpp
|
10 |
+
# CATCH_VERSION - version number
|
11 |
+
|
12 |
+
option(DOWNLOAD_CATCH "Download catch2 if not found")
|
13 |
+
|
14 |
+
if(NOT Catch_FIND_VERSION)
|
15 |
+
message(FATAL_ERROR "A version number must be specified.")
|
16 |
+
elseif(Catch_FIND_REQUIRED)
|
17 |
+
message(FATAL_ERROR "This module assumes Catch is not required.")
|
18 |
+
elseif(Catch_FIND_VERSION_EXACT)
|
19 |
+
message(FATAL_ERROR "Exact version numbers are not supported, only minimum.")
|
20 |
+
endif()
|
21 |
+
|
22 |
+
# Extract the version number from catch.hpp
|
23 |
+
function(_get_catch_version)
|
24 |
+
file(
|
25 |
+
STRINGS "${CATCH_INCLUDE_DIR}/catch.hpp" version_line
|
26 |
+
REGEX "Catch v.*"
|
27 |
+
LIMIT_COUNT 1)
|
28 |
+
if(version_line MATCHES "Catch v([0-9]+)\\.([0-9]+)\\.([0-9]+)")
|
29 |
+
set(CATCH_VERSION
|
30 |
+
"${CMAKE_MATCH_1}.${CMAKE_MATCH_2}.${CMAKE_MATCH_3}"
|
31 |
+
PARENT_SCOPE)
|
32 |
+
endif()
|
33 |
+
endfunction()
|
34 |
+
|
35 |
+
# Download the single-header version of Catch
|
36 |
+
function(_download_catch version destination_dir)
|
37 |
+
message(STATUS "Downloading catch v${version}...")
|
38 |
+
set(url https://github.com/philsquared/Catch/releases/download/v${version}/catch.hpp)
|
39 |
+
file(DOWNLOAD ${url} "${destination_dir}/catch.hpp" STATUS status)
|
40 |
+
list(GET status 0 error)
|
41 |
+
if(error)
|
42 |
+
message(FATAL_ERROR "Could not download ${url}")
|
43 |
+
endif()
|
44 |
+
set(CATCH_INCLUDE_DIR
|
45 |
+
"${destination_dir}"
|
46 |
+
CACHE INTERNAL "")
|
47 |
+
endfunction()
|
48 |
+
|
49 |
+
# Look for catch locally
|
50 |
+
find_path(
|
51 |
+
CATCH_INCLUDE_DIR
|
52 |
+
NAMES catch.hpp
|
53 |
+
PATH_SUFFIXES catch2)
|
54 |
+
if(CATCH_INCLUDE_DIR)
|
55 |
+
_get_catch_version()
|
56 |
+
endif()
|
57 |
+
|
58 |
+
# Download the header if it wasn't found or if it's outdated
|
59 |
+
if(NOT CATCH_VERSION OR CATCH_VERSION VERSION_LESS ${Catch_FIND_VERSION})
|
60 |
+
if(DOWNLOAD_CATCH)
|
61 |
+
_download_catch(${Catch_FIND_VERSION} "${PROJECT_BINARY_DIR}/catch/")
|
62 |
+
_get_catch_version()
|
63 |
+
else()
|
64 |
+
set(CATCH_FOUND FALSE)
|
65 |
+
return()
|
66 |
+
endif()
|
67 |
+
endif()
|
68 |
+
|
69 |
+
add_library(Catch2::Catch2 IMPORTED INTERFACE)
|
70 |
+
set_property(TARGET Catch2::Catch2 PROPERTY INTERFACE_INCLUDE_DIRECTORIES "${CATCH_INCLUDE_DIR}")
|
71 |
+
|
72 |
+
set(CATCH_FOUND TRUE)
|
third-party/DPVO/DPViewer/pybind11/tools/FindEigen3.cmake
ADDED
@@ -0,0 +1,86 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# - Try to find Eigen3 lib
|
2 |
+
#
|
3 |
+
# This module supports requiring a minimum version, e.g. you can do
|
4 |
+
# find_package(Eigen3 3.1.2)
|
5 |
+
# to require version 3.1.2 or newer of Eigen3.
|
6 |
+
#
|
7 |
+
# Once done this will define
|
8 |
+
#
|
9 |
+
# EIGEN3_FOUND - system has eigen lib with correct version
|
10 |
+
# EIGEN3_INCLUDE_DIR - the eigen include directory
|
11 |
+
# EIGEN3_VERSION - eigen version
|
12 |
+
|
13 |
+
# Copyright (c) 2006, 2007 Montel Laurent, <[email protected]>
|
14 |
+
# Copyright (c) 2008, 2009 Gael Guennebaud, <[email protected]>
|
15 |
+
# Copyright (c) 2009 Benoit Jacob <[email protected]>
|
16 |
+
# Redistribution and use is allowed according to the terms of the 2-clause BSD license.
|
17 |
+
|
18 |
+
if(NOT Eigen3_FIND_VERSION)
|
19 |
+
if(NOT Eigen3_FIND_VERSION_MAJOR)
|
20 |
+
set(Eigen3_FIND_VERSION_MAJOR 2)
|
21 |
+
endif(NOT Eigen3_FIND_VERSION_MAJOR)
|
22 |
+
if(NOT Eigen3_FIND_VERSION_MINOR)
|
23 |
+
set(Eigen3_FIND_VERSION_MINOR 91)
|
24 |
+
endif(NOT Eigen3_FIND_VERSION_MINOR)
|
25 |
+
if(NOT Eigen3_FIND_VERSION_PATCH)
|
26 |
+
set(Eigen3_FIND_VERSION_PATCH 0)
|
27 |
+
endif(NOT Eigen3_FIND_VERSION_PATCH)
|
28 |
+
|
29 |
+
set(Eigen3_FIND_VERSION
|
30 |
+
"${Eigen3_FIND_VERSION_MAJOR}.${Eigen3_FIND_VERSION_MINOR}.${Eigen3_FIND_VERSION_PATCH}")
|
31 |
+
endif(NOT Eigen3_FIND_VERSION)
|
32 |
+
|
33 |
+
macro(_eigen3_check_version)
|
34 |
+
file(READ "${EIGEN3_INCLUDE_DIR}/Eigen/src/Core/util/Macros.h" _eigen3_version_header)
|
35 |
+
|
36 |
+
string(REGEX MATCH "define[ \t]+EIGEN_WORLD_VERSION[ \t]+([0-9]+)" _eigen3_world_version_match
|
37 |
+
"${_eigen3_version_header}")
|
38 |
+
set(EIGEN3_WORLD_VERSION "${CMAKE_MATCH_1}")
|
39 |
+
string(REGEX MATCH "define[ \t]+EIGEN_MAJOR_VERSION[ \t]+([0-9]+)" _eigen3_major_version_match
|
40 |
+
"${_eigen3_version_header}")
|
41 |
+
set(EIGEN3_MAJOR_VERSION "${CMAKE_MATCH_1}")
|
42 |
+
string(REGEX MATCH "define[ \t]+EIGEN_MINOR_VERSION[ \t]+([0-9]+)" _eigen3_minor_version_match
|
43 |
+
"${_eigen3_version_header}")
|
44 |
+
set(EIGEN3_MINOR_VERSION "${CMAKE_MATCH_1}")
|
45 |
+
|
46 |
+
set(EIGEN3_VERSION ${EIGEN3_WORLD_VERSION}.${EIGEN3_MAJOR_VERSION}.${EIGEN3_MINOR_VERSION})
|
47 |
+
if(${EIGEN3_VERSION} VERSION_LESS ${Eigen3_FIND_VERSION})
|
48 |
+
set(EIGEN3_VERSION_OK FALSE)
|
49 |
+
else(${EIGEN3_VERSION} VERSION_LESS ${Eigen3_FIND_VERSION})
|
50 |
+
set(EIGEN3_VERSION_OK TRUE)
|
51 |
+
endif(${EIGEN3_VERSION} VERSION_LESS ${Eigen3_FIND_VERSION})
|
52 |
+
|
53 |
+
if(NOT EIGEN3_VERSION_OK)
|
54 |
+
|
55 |
+
message(STATUS "Eigen3 version ${EIGEN3_VERSION} found in ${EIGEN3_INCLUDE_DIR}, "
|
56 |
+
"but at least version ${Eigen3_FIND_VERSION} is required")
|
57 |
+
endif(NOT EIGEN3_VERSION_OK)
|
58 |
+
endmacro(_eigen3_check_version)
|
59 |
+
|
60 |
+
if(EIGEN3_INCLUDE_DIR)
|
61 |
+
|
62 |
+
# in cache already
|
63 |
+
_eigen3_check_version()
|
64 |
+
set(EIGEN3_FOUND ${EIGEN3_VERSION_OK})
|
65 |
+
|
66 |
+
else(EIGEN3_INCLUDE_DIR)
|
67 |
+
if(NOT DEFINED KDE4_INCLUDE_DIR)
|
68 |
+
set(KDE4_INCLUDE_DIR "")
|
69 |
+
endif()
|
70 |
+
|
71 |
+
find_path(
|
72 |
+
EIGEN3_INCLUDE_DIR
|
73 |
+
NAMES signature_of_eigen3_matrix_library
|
74 |
+
PATHS ${CMAKE_INSTALL_PREFIX}/include ${KDE4_INCLUDE_DIR}
|
75 |
+
PATH_SUFFIXES eigen3 eigen)
|
76 |
+
|
77 |
+
if(EIGEN3_INCLUDE_DIR)
|
78 |
+
_eigen3_check_version()
|
79 |
+
endif(EIGEN3_INCLUDE_DIR)
|
80 |
+
|
81 |
+
include(FindPackageHandleStandardArgs)
|
82 |
+
find_package_handle_standard_args(Eigen3 DEFAULT_MSG EIGEN3_INCLUDE_DIR EIGEN3_VERSION_OK)
|
83 |
+
|
84 |
+
mark_as_advanced(EIGEN3_INCLUDE_DIR)
|
85 |
+
|
86 |
+
endif(EIGEN3_INCLUDE_DIR)
|
third-party/DPVO/DPViewer/pybind11/tools/FindPythonLibsNew.cmake
ADDED
@@ -0,0 +1,281 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# - Find python libraries
|
2 |
+
# This module finds the libraries corresponding to the Python interpreter
|
3 |
+
# FindPythonInterp provides.
|
4 |
+
# This code sets the following variables:
|
5 |
+
#
|
6 |
+
# PYTHONLIBS_FOUND - have the Python libs been found
|
7 |
+
# PYTHON_PREFIX - path to the Python installation
|
8 |
+
# PYTHON_LIBRARIES - path to the python library
|
9 |
+
# PYTHON_INCLUDE_DIRS - path to where Python.h is found
|
10 |
+
# PYTHON_MODULE_EXTENSION - lib extension, e.g. '.so' or '.pyd'
|
11 |
+
# PYTHON_MODULE_PREFIX - lib name prefix: usually an empty string
|
12 |
+
# PYTHON_SITE_PACKAGES - path to installation site-packages
|
13 |
+
# PYTHON_IS_DEBUG - whether the Python interpreter is a debug build
|
14 |
+
#
|
15 |
+
# Thanks to talljimbo for the patch adding the 'LDVERSION' config
|
16 |
+
# variable usage.
|
17 |
+
|
18 |
+
#=============================================================================
|
19 |
+
# Copyright 2001-2009 Kitware, Inc.
|
20 |
+
# Copyright 2012 Continuum Analytics, Inc.
|
21 |
+
#
|
22 |
+
# All rights reserved.
|
23 |
+
#
|
24 |
+
# Redistribution and use in source and binary forms, with or without
|
25 |
+
# modification, are permitted provided that the following conditions
|
26 |
+
# are met:
|
27 |
+
#
|
28 |
+
# * Redistributions of source code must retain the above copyright
|
29 |
+
# notice, this list of conditions and the following disclaimer.
|
30 |
+
#
|
31 |
+
# * Redistributions in binary form must reproduce the above copyright
|
32 |
+
# notice, this list of conditions and the following disclaimer in the
|
33 |
+
# documentation and/or other materials provided with the distribution.
|
34 |
+
#
|
35 |
+
# * Neither the names of Kitware, Inc., the Insight Software Consortium,
|
36 |
+
# nor the names of their contributors may be used to endorse or promote
|
37 |
+
# products derived from this software without specific prior written
|
38 |
+
# permission.
|
39 |
+
#
|
40 |
+
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
41 |
+
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
42 |
+
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
43 |
+
# # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
44 |
+
# HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
45 |
+
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
46 |
+
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
47 |
+
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
48 |
+
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
49 |
+
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
50 |
+
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
51 |
+
#=============================================================================
|
52 |
+
|
53 |
+
# Checking for the extension makes sure that `LibsNew` was found and not just `Libs`.
|
54 |
+
if(PYTHONLIBS_FOUND AND PYTHON_MODULE_EXTENSION)
|
55 |
+
return()
|
56 |
+
endif()
|
57 |
+
|
58 |
+
if(PythonLibsNew_FIND_QUIETLY)
|
59 |
+
set(_pythonlibs_quiet QUIET)
|
60 |
+
else()
|
61 |
+
set(_pythonlibs_quiet "")
|
62 |
+
endif()
|
63 |
+
|
64 |
+
if(PythonLibsNew_FIND_REQUIRED)
|
65 |
+
set(_pythonlibs_required REQUIRED)
|
66 |
+
endif()
|
67 |
+
|
68 |
+
# Check to see if the `python` command is present and from a virtual
|
69 |
+
# environment, conda, or GHA activation - if it is, try to use that.
|
70 |
+
|
71 |
+
if(NOT DEFINED PYTHON_EXECUTABLE)
|
72 |
+
if(DEFINED ENV{VIRTUAL_ENV})
|
73 |
+
find_program(
|
74 |
+
PYTHON_EXECUTABLE python
|
75 |
+
PATHS "$ENV{VIRTUAL_ENV}" "$ENV{VIRTUAL_ENV}/bin"
|
76 |
+
NO_DEFAULT_PATH)
|
77 |
+
elseif(DEFINED ENV{CONDA_PREFIX})
|
78 |
+
find_program(
|
79 |
+
PYTHON_EXECUTABLE python
|
80 |
+
PATHS "$ENV{CONDA_PREFIX}" "$ENV{CONDA_PREFIX}/bin"
|
81 |
+
NO_DEFAULT_PATH)
|
82 |
+
elseif(DEFINED ENV{pythonLocation})
|
83 |
+
find_program(
|
84 |
+
PYTHON_EXECUTABLE python
|
85 |
+
PATHS "$ENV{pythonLocation}" "$ENV{pythonLocation}/bin"
|
86 |
+
NO_DEFAULT_PATH)
|
87 |
+
endif()
|
88 |
+
if(NOT PYTHON_EXECUTABLE)
|
89 |
+
unset(PYTHON_EXECUTABLE)
|
90 |
+
endif()
|
91 |
+
endif()
|
92 |
+
|
93 |
+
# Use the Python interpreter to find the libs.
|
94 |
+
if(NOT PythonLibsNew_FIND_VERSION)
|
95 |
+
set(PythonLibsNew_FIND_VERSION "3.6")
|
96 |
+
endif()
|
97 |
+
|
98 |
+
find_package(PythonInterp ${PythonLibsNew_FIND_VERSION} ${_pythonlibs_required}
|
99 |
+
${_pythonlibs_quiet})
|
100 |
+
|
101 |
+
if(NOT PYTHONINTERP_FOUND)
|
102 |
+
set(PYTHONLIBS_FOUND FALSE)
|
103 |
+
set(PythonLibsNew_FOUND FALSE)
|
104 |
+
return()
|
105 |
+
endif()
|
106 |
+
|
107 |
+
# According to https://stackoverflow.com/questions/646518/python-how-to-detect-debug-interpreter
|
108 |
+
# testing whether sys has the gettotalrefcount function is a reliable, cross-platform
|
109 |
+
# way to detect a CPython debug interpreter.
|
110 |
+
#
|
111 |
+
# The library suffix is from the config var LDVERSION sometimes, otherwise
|
112 |
+
# VERSION. VERSION will typically be like "2.7" on unix, and "27" on windows.
|
113 |
+
execute_process(
|
114 |
+
COMMAND
|
115 |
+
"${PYTHON_EXECUTABLE}" "-c" "
|
116 |
+
import sys;import struct;
|
117 |
+
import sysconfig as s
|
118 |
+
USE_SYSCONFIG = sys.version_info >= (3, 10)
|
119 |
+
if not USE_SYSCONFIG:
|
120 |
+
from distutils import sysconfig as ds
|
121 |
+
print('.'.join(str(v) for v in sys.version_info));
|
122 |
+
print(sys.prefix);
|
123 |
+
if USE_SYSCONFIG:
|
124 |
+
scheme = s.get_default_scheme()
|
125 |
+
if scheme == 'posix_local':
|
126 |
+
# Debian's default scheme installs to /usr/local/ but we want to find headers in /usr/
|
127 |
+
scheme = 'posix_prefix'
|
128 |
+
print(s.get_path('platinclude', scheme))
|
129 |
+
print(s.get_path('platlib'))
|
130 |
+
print(s.get_config_var('EXT_SUFFIX') or s.get_config_var('SO'))
|
131 |
+
else:
|
132 |
+
print(ds.get_python_inc(plat_specific=True));
|
133 |
+
print(ds.get_python_lib(plat_specific=True));
|
134 |
+
print(ds.get_config_var('EXT_SUFFIX') or ds.get_config_var('SO'));
|
135 |
+
print(hasattr(sys, 'gettotalrefcount')+0);
|
136 |
+
print(struct.calcsize('@P'));
|
137 |
+
print(s.get_config_var('LDVERSION') or s.get_config_var('VERSION'));
|
138 |
+
print(s.get_config_var('LIBDIR') or '');
|
139 |
+
print(s.get_config_var('MULTIARCH') or '');
|
140 |
+
"
|
141 |
+
RESULT_VARIABLE _PYTHON_SUCCESS
|
142 |
+
OUTPUT_VARIABLE _PYTHON_VALUES
|
143 |
+
ERROR_VARIABLE _PYTHON_ERROR_VALUE)
|
144 |
+
|
145 |
+
if(NOT _PYTHON_SUCCESS MATCHES 0)
|
146 |
+
if(PythonLibsNew_FIND_REQUIRED)
|
147 |
+
message(FATAL_ERROR "Python config failure:\n${_PYTHON_ERROR_VALUE}")
|
148 |
+
endif()
|
149 |
+
set(PYTHONLIBS_FOUND FALSE)
|
150 |
+
set(PythonLibsNew_FOUND FALSE)
|
151 |
+
return()
|
152 |
+
endif()
|
153 |
+
|
154 |
+
# Can manually set values when cross-compiling
|
155 |
+
macro(_PYBIND11_GET_IF_UNDEF lst index name)
|
156 |
+
if(NOT DEFINED "${name}")
|
157 |
+
list(GET "${lst}" "${index}" "${name}")
|
158 |
+
endif()
|
159 |
+
endmacro()
|
160 |
+
|
161 |
+
# Convert the process output into a list
|
162 |
+
if(WIN32)
|
163 |
+
string(REGEX REPLACE "\\\\" "/" _PYTHON_VALUES ${_PYTHON_VALUES})
|
164 |
+
endif()
|
165 |
+
string(REGEX REPLACE ";" "\\\\;" _PYTHON_VALUES ${_PYTHON_VALUES})
|
166 |
+
string(REGEX REPLACE "\n" ";" _PYTHON_VALUES ${_PYTHON_VALUES})
|
167 |
+
_pybind11_get_if_undef(_PYTHON_VALUES 0 _PYTHON_VERSION_LIST)
|
168 |
+
_pybind11_get_if_undef(_PYTHON_VALUES 1 PYTHON_PREFIX)
|
169 |
+
_pybind11_get_if_undef(_PYTHON_VALUES 2 PYTHON_INCLUDE_DIR)
|
170 |
+
_pybind11_get_if_undef(_PYTHON_VALUES 3 PYTHON_SITE_PACKAGES)
|
171 |
+
_pybind11_get_if_undef(_PYTHON_VALUES 4 PYTHON_MODULE_EXTENSION)
|
172 |
+
_pybind11_get_if_undef(_PYTHON_VALUES 5 PYTHON_IS_DEBUG)
|
173 |
+
_pybind11_get_if_undef(_PYTHON_VALUES 6 PYTHON_SIZEOF_VOID_P)
|
174 |
+
_pybind11_get_if_undef(_PYTHON_VALUES 7 PYTHON_LIBRARY_SUFFIX)
|
175 |
+
_pybind11_get_if_undef(_PYTHON_VALUES 8 PYTHON_LIBDIR)
|
176 |
+
_pybind11_get_if_undef(_PYTHON_VALUES 9 PYTHON_MULTIARCH)
|
177 |
+
|
178 |
+
# Make sure the Python has the same pointer-size as the chosen compiler
|
179 |
+
# Skip if CMAKE_SIZEOF_VOID_P is not defined
|
180 |
+
# This should be skipped for (non-Apple) cross-compiles (like EMSCRIPTEN)
|
181 |
+
if(NOT CMAKE_CROSSCOMPILING
|
182 |
+
AND CMAKE_SIZEOF_VOID_P
|
183 |
+
AND (NOT "${PYTHON_SIZEOF_VOID_P}" STREQUAL "${CMAKE_SIZEOF_VOID_P}"))
|
184 |
+
if(PythonLibsNew_FIND_REQUIRED)
|
185 |
+
math(EXPR _PYTHON_BITS "${PYTHON_SIZEOF_VOID_P} * 8")
|
186 |
+
math(EXPR _CMAKE_BITS "${CMAKE_SIZEOF_VOID_P} * 8")
|
187 |
+
message(FATAL_ERROR "Python config failure: Python is ${_PYTHON_BITS}-bit, "
|
188 |
+
"chosen compiler is ${_CMAKE_BITS}-bit")
|
189 |
+
endif()
|
190 |
+
set(PYTHONLIBS_FOUND FALSE)
|
191 |
+
set(PythonLibsNew_FOUND FALSE)
|
192 |
+
return()
|
193 |
+
endif()
|
194 |
+
|
195 |
+
# The built-in FindPython didn't always give the version numbers
|
196 |
+
string(REGEX REPLACE "\\." ";" _PYTHON_VERSION_LIST ${_PYTHON_VERSION_LIST})
|
197 |
+
list(GET _PYTHON_VERSION_LIST 0 PYTHON_VERSION_MAJOR)
|
198 |
+
list(GET _PYTHON_VERSION_LIST 1 PYTHON_VERSION_MINOR)
|
199 |
+
list(GET _PYTHON_VERSION_LIST 2 PYTHON_VERSION_PATCH)
|
200 |
+
set(PYTHON_VERSION "${PYTHON_VERSION_MAJOR}.${PYTHON_VERSION_MINOR}.${PYTHON_VERSION_PATCH}")
|
201 |
+
|
202 |
+
# Make sure all directory separators are '/'
|
203 |
+
string(REGEX REPLACE "\\\\" "/" PYTHON_PREFIX "${PYTHON_PREFIX}")
|
204 |
+
string(REGEX REPLACE "\\\\" "/" PYTHON_INCLUDE_DIR "${PYTHON_INCLUDE_DIR}")
|
205 |
+
string(REGEX REPLACE "\\\\" "/" PYTHON_SITE_PACKAGES "${PYTHON_SITE_PACKAGES}")
|
206 |
+
|
207 |
+
if(CMAKE_HOST_WIN32)
|
208 |
+
set(PYTHON_LIBRARY "${PYTHON_PREFIX}/libs/python${PYTHON_LIBRARY_SUFFIX}.lib")
|
209 |
+
|
210 |
+
# when run in a venv, PYTHON_PREFIX points to it. But the libraries remain in the
|
211 |
+
# original python installation. They may be found relative to PYTHON_INCLUDE_DIR.
|
212 |
+
if(NOT EXISTS "${PYTHON_LIBRARY}")
|
213 |
+
get_filename_component(_PYTHON_ROOT ${PYTHON_INCLUDE_DIR} DIRECTORY)
|
214 |
+
set(PYTHON_LIBRARY "${_PYTHON_ROOT}/libs/python${PYTHON_LIBRARY_SUFFIX}.lib")
|
215 |
+
endif()
|
216 |
+
|
217 |
+
# if we are in MSYS & MINGW, and we didn't find windows python lib, look for system python lib
|
218 |
+
if(DEFINED ENV{MSYSTEM}
|
219 |
+
AND MINGW
|
220 |
+
AND NOT EXISTS "${PYTHON_LIBRARY}")
|
221 |
+
if(PYTHON_MULTIARCH)
|
222 |
+
set(_PYTHON_LIBS_SEARCH "${PYTHON_LIBDIR}/${PYTHON_MULTIARCH}" "${PYTHON_LIBDIR}")
|
223 |
+
else()
|
224 |
+
set(_PYTHON_LIBS_SEARCH "${PYTHON_LIBDIR}")
|
225 |
+
endif()
|
226 |
+
unset(PYTHON_LIBRARY)
|
227 |
+
find_library(
|
228 |
+
PYTHON_LIBRARY
|
229 |
+
NAMES "python${PYTHON_LIBRARY_SUFFIX}"
|
230 |
+
PATHS ${_PYTHON_LIBS_SEARCH}
|
231 |
+
NO_DEFAULT_PATH)
|
232 |
+
endif()
|
233 |
+
|
234 |
+
# raise an error if the python libs are still not found.
|
235 |
+
if(NOT EXISTS "${PYTHON_LIBRARY}")
|
236 |
+
message(FATAL_ERROR "Python libraries not found")
|
237 |
+
endif()
|
238 |
+
|
239 |
+
else()
|
240 |
+
if(PYTHON_MULTIARCH)
|
241 |
+
set(_PYTHON_LIBS_SEARCH "${PYTHON_LIBDIR}/${PYTHON_MULTIARCH}" "${PYTHON_LIBDIR}")
|
242 |
+
else()
|
243 |
+
set(_PYTHON_LIBS_SEARCH "${PYTHON_LIBDIR}")
|
244 |
+
endif()
|
245 |
+
#message(STATUS "Searching for Python libs in ${_PYTHON_LIBS_SEARCH}")
|
246 |
+
# Probably this needs to be more involved. It would be nice if the config
|
247 |
+
# information the python interpreter itself gave us were more complete.
|
248 |
+
find_library(
|
249 |
+
PYTHON_LIBRARY
|
250 |
+
NAMES "python${PYTHON_LIBRARY_SUFFIX}"
|
251 |
+
PATHS ${_PYTHON_LIBS_SEARCH}
|
252 |
+
NO_DEFAULT_PATH)
|
253 |
+
|
254 |
+
# If all else fails, just set the name/version and let the linker figure out the path.
|
255 |
+
if(NOT PYTHON_LIBRARY)
|
256 |
+
set(PYTHON_LIBRARY python${PYTHON_LIBRARY_SUFFIX})
|
257 |
+
endif()
|
258 |
+
endif()
|
259 |
+
|
260 |
+
mark_as_advanced(PYTHON_LIBRARY PYTHON_INCLUDE_DIR)
|
261 |
+
|
262 |
+
# We use PYTHON_INCLUDE_DIR, PYTHON_LIBRARY and PYTHON_DEBUG_LIBRARY for the
|
263 |
+
# cache entries because they are meant to specify the location of a single
|
264 |
+
# library. We now set the variables listed by the documentation for this
|
265 |
+
# module.
|
266 |
+
set(PYTHON_INCLUDE_DIRS "${PYTHON_INCLUDE_DIR}")
|
267 |
+
set(PYTHON_LIBRARIES "${PYTHON_LIBRARY}")
|
268 |
+
if(NOT PYTHON_DEBUG_LIBRARY)
|
269 |
+
set(PYTHON_DEBUG_LIBRARY "")
|
270 |
+
endif()
|
271 |
+
set(PYTHON_DEBUG_LIBRARIES "${PYTHON_DEBUG_LIBRARY}")
|
272 |
+
|
273 |
+
find_package_message(PYTHON "Found PythonLibs: ${PYTHON_LIBRARY}"
|
274 |
+
"${PYTHON_EXECUTABLE}${PYTHON_VERSION_STRING}")
|
275 |
+
|
276 |
+
set(PYTHONLIBS_FOUND TRUE)
|
277 |
+
set(PythonLibsNew_FOUND TRUE)
|
278 |
+
|
279 |
+
if(NOT PYTHON_MODULE_PREFIX)
|
280 |
+
set(PYTHON_MODULE_PREFIX "")
|
281 |
+
endif()
|
third-party/DPVO/DPViewer/pybind11/tools/check-style.sh
ADDED
@@ -0,0 +1,44 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
#!/bin/bash
|
2 |
+
#
|
3 |
+
# Script to check include/test code for common pybind11 code style errors.
|
4 |
+
#
|
5 |
+
# This script currently checks for
|
6 |
+
#
|
7 |
+
# 1. missing space between keyword and parenthesis, e.g.: for(, if(, while(
|
8 |
+
# 2. Missing space between right parenthesis and brace, e.g. 'for (...){'
|
9 |
+
# 3. opening brace on its own line. It should always be on the same line as the
|
10 |
+
# if/while/for/do statement.
|
11 |
+
#
|
12 |
+
# Invoke as: tools/check-style.sh <filenames>
|
13 |
+
#
|
14 |
+
|
15 |
+
check_style_errors=0
|
16 |
+
IFS=$'\n'
|
17 |
+
|
18 |
+
|
19 |
+
found="$(grep '\<\(if\|for\|while\|catch\)(\|){' "$@" -rn --color=always)"
|
20 |
+
if [ -n "$found" ]; then
|
21 |
+
echo -e '\033[31;01mError: found the following coding style problems:\033[0m'
|
22 |
+
check_style_errors=1
|
23 |
+
echo "${found//^/ /}"
|
24 |
+
fi
|
25 |
+
|
26 |
+
found="$(awk '
|
27 |
+
function prefix(filename, lineno) {
|
28 |
+
return " \033[35m" filename "\033[36m:\033[32m" lineno "\033[36m:\033[0m"
|
29 |
+
}
|
30 |
+
function mark(pattern, string) { sub(pattern, "\033[01;31m&\033[0m", string); return string }
|
31 |
+
last && /^\s*{/ {
|
32 |
+
print prefix(FILENAME, FNR-1) mark("\\)\\s*$", last)
|
33 |
+
print prefix(FILENAME, FNR) mark("^\\s*{", $0)
|
34 |
+
last=""
|
35 |
+
}
|
36 |
+
{ last = /(if|for|while|catch|switch)\s*\(.*\)\s*$/ ? $0 : "" }
|
37 |
+
' "$(find include -type f)" "$@")"
|
38 |
+
if [ -n "$found" ]; then
|
39 |
+
check_style_errors=1
|
40 |
+
echo -e '\033[31;01mError: braces should occur on the same line as the if/while/.. statement. Found issues in the following files:\033[0m'
|
41 |
+
echo "$found"
|
42 |
+
fi
|
43 |
+
|
44 |
+
exit $check_style_errors
|
third-party/DPVO/DPViewer/pybind11/tools/cmake_uninstall.cmake.in
ADDED
@@ -0,0 +1,23 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# Source: https://gitlab.kitware.com/cmake/community/-/wikis/FAQ#can-i-do-make-uninstall-with-cmake
|
2 |
+
|
3 |
+
if(NOT EXISTS "@CMAKE_BINARY_DIR@/install_manifest.txt")
|
4 |
+
message(FATAL_ERROR "Cannot find install manifest: @CMAKE_BINARY_DIR@/install_manifest.txt")
|
5 |
+
endif()
|
6 |
+
|
7 |
+
file(READ "@CMAKE_BINARY_DIR@/install_manifest.txt" files)
|
8 |
+
string(REGEX REPLACE "\n" ";" files "${files}")
|
9 |
+
foreach(file ${files})
|
10 |
+
message(STATUS "Uninstalling $ENV{DESTDIR}${file}")
|
11 |
+
if(IS_SYMLINK "$ENV{DESTDIR}${file}" OR EXISTS "$ENV{DESTDIR}${file}")
|
12 |
+
exec_program(
|
13 |
+
"@CMAKE_COMMAND@" ARGS
|
14 |
+
"-E remove \"$ENV{DESTDIR}${file}\""
|
15 |
+
OUTPUT_VARIABLE rm_out
|
16 |
+
RETURN_VALUE rm_retval)
|
17 |
+
if(NOT "${rm_retval}" STREQUAL 0)
|
18 |
+
message(FATAL_ERROR "Problem when removing $ENV{DESTDIR}${file}")
|
19 |
+
endif()
|
20 |
+
else(IS_SYMLINK "$ENV{DESTDIR}${file}" OR EXISTS "$ENV{DESTDIR}${file}")
|
21 |
+
message(STATUS "File $ENV{DESTDIR}${file} does not exist.")
|
22 |
+
endif()
|
23 |
+
endforeach()
|
third-party/DPVO/DPViewer/pybind11/tools/libsize.py
ADDED
@@ -0,0 +1,36 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import os
|
2 |
+
import sys
|
3 |
+
|
4 |
+
# Internal build script for generating debugging test .so size.
|
5 |
+
# Usage:
|
6 |
+
# python libsize.py file.so save.txt -- displays the size of file.so and, if save.txt exists, compares it to the
|
7 |
+
# size in it, then overwrites save.txt with the new size for future runs.
|
8 |
+
|
9 |
+
if len(sys.argv) != 3:
|
10 |
+
sys.exit("Invalid arguments: usage: python libsize.py file.so save.txt")
|
11 |
+
|
12 |
+
lib = sys.argv[1]
|
13 |
+
save = sys.argv[2]
|
14 |
+
|
15 |
+
if not os.path.exists(lib):
|
16 |
+
sys.exit(f"Error: requested file ({lib}) does not exist")
|
17 |
+
|
18 |
+
libsize = os.path.getsize(lib)
|
19 |
+
|
20 |
+
print("------", os.path.basename(lib), "file size:", libsize, end="")
|
21 |
+
|
22 |
+
if os.path.exists(save):
|
23 |
+
with open(save) as sf:
|
24 |
+
oldsize = int(sf.readline())
|
25 |
+
|
26 |
+
if oldsize > 0:
|
27 |
+
change = libsize - oldsize
|
28 |
+
if change == 0:
|
29 |
+
print(" (no change)")
|
30 |
+
else:
|
31 |
+
print(f" (change of {change:+} bytes = {change / oldsize:+.2%})")
|
32 |
+
else:
|
33 |
+
print()
|
34 |
+
|
35 |
+
with open(save, "w") as sf:
|
36 |
+
sf.write(str(libsize))
|
third-party/DPVO/DPViewer/pybind11/tools/make_changelog.py
ADDED
@@ -0,0 +1,63 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
#!/usr/bin/env python3
|
2 |
+
|
3 |
+
import re
|
4 |
+
|
5 |
+
import ghapi.all
|
6 |
+
from rich import print
|
7 |
+
from rich.syntax import Syntax
|
8 |
+
|
9 |
+
ENTRY = re.compile(
|
10 |
+
r"""
|
11 |
+
Suggested \s changelog \s entry:
|
12 |
+
.*
|
13 |
+
```rst
|
14 |
+
\s*
|
15 |
+
(.*?)
|
16 |
+
\s*
|
17 |
+
```
|
18 |
+
""",
|
19 |
+
re.DOTALL | re.VERBOSE,
|
20 |
+
)
|
21 |
+
|
22 |
+
print()
|
23 |
+
|
24 |
+
|
25 |
+
api = ghapi.all.GhApi(owner="pybind", repo="pybind11")
|
26 |
+
|
27 |
+
issues_pages = ghapi.page.paged(
|
28 |
+
api.issues.list_for_repo, labels="needs changelog", state="closed"
|
29 |
+
)
|
30 |
+
issues = (issue for page in issues_pages for issue in page)
|
31 |
+
missing = []
|
32 |
+
|
33 |
+
for issue in issues:
|
34 |
+
changelog = ENTRY.findall(issue.body)
|
35 |
+
if changelog:
|
36 |
+
(msg,) = changelog
|
37 |
+
if not msg.startswith("* "):
|
38 |
+
msg = "* " + msg
|
39 |
+
if not msg.endswith("."):
|
40 |
+
msg += "."
|
41 |
+
|
42 |
+
msg += f"\n `#{issue.number} <{issue.html_url}>`_"
|
43 |
+
|
44 |
+
print(Syntax(msg, "rst", theme="ansi_light", word_wrap=True))
|
45 |
+
print()
|
46 |
+
|
47 |
+
else:
|
48 |
+
missing.append(issue)
|
49 |
+
|
50 |
+
if missing:
|
51 |
+
print()
|
52 |
+
print("[blue]" + "-" * 30)
|
53 |
+
print()
|
54 |
+
|
55 |
+
for issue in missing:
|
56 |
+
print(f"[red bold]Missing:[/red bold][red] {issue.title}")
|
57 |
+
print(f"[red] {issue.html_url}\n")
|
58 |
+
|
59 |
+
print("[bold]Template:\n")
|
60 |
+
msg = "## Suggested changelog entry:\n\n```rst\n\n```"
|
61 |
+
print(Syntax(msg, "md", theme="ansi_light"))
|
62 |
+
|
63 |
+
print()
|
third-party/DPVO/DPViewer/pybind11/tools/pybind11Common.cmake
ADDED
@@ -0,0 +1,385 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
#[======================================================[.rst
|
2 |
+
|
3 |
+
Adds the following targets::
|
4 |
+
|
5 |
+
pybind11::pybind11 - link to headers and pybind11
|
6 |
+
pybind11::module - Adds module links
|
7 |
+
pybind11::embed - Adds embed links
|
8 |
+
pybind11::lto - Link time optimizations (manual selection)
|
9 |
+
pybind11::thin_lto - Link time optimizations (manual selection)
|
10 |
+
pybind11::python_link_helper - Adds link to Python libraries
|
11 |
+
pybind11::windows_extras - MSVC bigobj and mp for building multithreaded
|
12 |
+
pybind11::opt_size - avoid optimizations that increase code size
|
13 |
+
|
14 |
+
Adds the following functions::
|
15 |
+
|
16 |
+
pybind11_strip(target) - strip target after building on linux/macOS
|
17 |
+
pybind11_find_import(module) - See if a module is installed.
|
18 |
+
|
19 |
+
#]======================================================]
|
20 |
+
|
21 |
+
# CMake 3.10 has an include_guard command, but we can't use that yet
|
22 |
+
# include_guard(global) (pre-CMake 3.10)
|
23 |
+
if(TARGET pybind11::lto)
|
24 |
+
return()
|
25 |
+
endif()
|
26 |
+
|
27 |
+
# If we are in subdirectory mode, all IMPORTED targets must be GLOBAL. If we
|
28 |
+
# are in CONFIG mode, they should be "normal" targets instead.
|
29 |
+
# In CMake 3.11+ you can promote a target to global after you create it,
|
30 |
+
# which might be simpler than this check.
|
31 |
+
get_property(
|
32 |
+
is_config
|
33 |
+
TARGET pybind11::headers
|
34 |
+
PROPERTY IMPORTED)
|
35 |
+
if(NOT is_config)
|
36 |
+
set(optional_global GLOBAL)
|
37 |
+
endif()
|
38 |
+
|
39 |
+
# If not run in Python mode, we still would like this to at least
|
40 |
+
# include pybind11's include directory:
|
41 |
+
set(pybind11_INCLUDE_DIRS
|
42 |
+
"${pybind11_INCLUDE_DIR}"
|
43 |
+
CACHE INTERNAL "Include directory for pybind11 (Python not requested)")
|
44 |
+
|
45 |
+
# --------------------- Shared targets ----------------------------
|
46 |
+
|
47 |
+
# Build an interface library target:
|
48 |
+
add_library(pybind11::pybind11 IMPORTED INTERFACE ${optional_global})
|
49 |
+
set_property(
|
50 |
+
TARGET pybind11::pybind11
|
51 |
+
APPEND
|
52 |
+
PROPERTY INTERFACE_LINK_LIBRARIES pybind11::headers)
|
53 |
+
|
54 |
+
# Build a module target:
|
55 |
+
add_library(pybind11::module IMPORTED INTERFACE ${optional_global})
|
56 |
+
set_property(
|
57 |
+
TARGET pybind11::module
|
58 |
+
APPEND
|
59 |
+
PROPERTY INTERFACE_LINK_LIBRARIES pybind11::pybind11)
|
60 |
+
|
61 |
+
# Build an embed library target:
|
62 |
+
add_library(pybind11::embed IMPORTED INTERFACE ${optional_global})
|
63 |
+
set_property(
|
64 |
+
TARGET pybind11::embed
|
65 |
+
APPEND
|
66 |
+
PROPERTY INTERFACE_LINK_LIBRARIES pybind11::pybind11)
|
67 |
+
|
68 |
+
# --------------------------- link helper ---------------------------
|
69 |
+
|
70 |
+
add_library(pybind11::python_link_helper IMPORTED INTERFACE ${optional_global})
|
71 |
+
|
72 |
+
if(CMAKE_VERSION VERSION_LESS 3.13)
|
73 |
+
# In CMake 3.11+, you can set INTERFACE properties via the normal methods, and
|
74 |
+
# this would be simpler.
|
75 |
+
set_property(
|
76 |
+
TARGET pybind11::python_link_helper
|
77 |
+
APPEND
|
78 |
+
PROPERTY INTERFACE_LINK_LIBRARIES "$<$<PLATFORM_ID:Darwin>:-undefined dynamic_lookup>")
|
79 |
+
else()
|
80 |
+
# link_options was added in 3.13+
|
81 |
+
# This is safer, because you are ensured the deduplication pass in CMake will not consider
|
82 |
+
# these separate and remove one but not the other.
|
83 |
+
set_property(
|
84 |
+
TARGET pybind11::python_link_helper
|
85 |
+
APPEND
|
86 |
+
PROPERTY INTERFACE_LINK_OPTIONS "$<$<PLATFORM_ID:Darwin>:LINKER:-undefined,dynamic_lookup>")
|
87 |
+
endif()
|
88 |
+
|
89 |
+
# ------------------------ Windows extras -------------------------
|
90 |
+
|
91 |
+
add_library(pybind11::windows_extras IMPORTED INTERFACE ${optional_global})
|
92 |
+
|
93 |
+
if(MSVC) # That's also clang-cl
|
94 |
+
# /bigobj is needed for bigger binding projects due to the limit to 64k
|
95 |
+
# addressable sections
|
96 |
+
set_property(
|
97 |
+
TARGET pybind11::windows_extras
|
98 |
+
APPEND
|
99 |
+
PROPERTY INTERFACE_COMPILE_OPTIONS $<$<COMPILE_LANGUAGE:CXX>:/bigobj>)
|
100 |
+
|
101 |
+
# /MP enables multithreaded builds (relevant when there are many files) for MSVC
|
102 |
+
if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") # no Clang no Intel
|
103 |
+
if(CMAKE_VERSION VERSION_LESS 3.11)
|
104 |
+
set_property(
|
105 |
+
TARGET pybind11::windows_extras
|
106 |
+
APPEND
|
107 |
+
PROPERTY INTERFACE_COMPILE_OPTIONS $<$<NOT:$<CONFIG:Debug>>:/MP>)
|
108 |
+
else()
|
109 |
+
# Only set these options for C++ files. This is important so that, for
|
110 |
+
# instance, projects that include other types of source files like CUDA
|
111 |
+
# .cu files don't get these options propagated to nvcc since that would
|
112 |
+
# cause the build to fail.
|
113 |
+
set_property(
|
114 |
+
TARGET pybind11::windows_extras
|
115 |
+
APPEND
|
116 |
+
PROPERTY INTERFACE_COMPILE_OPTIONS
|
117 |
+
$<$<NOT:$<CONFIG:Debug>>:$<$<COMPILE_LANGUAGE:CXX>:/MP>>)
|
118 |
+
endif()
|
119 |
+
endif()
|
120 |
+
endif()
|
121 |
+
|
122 |
+
# ----------------------- Optimize binary size --------------------------
|
123 |
+
|
124 |
+
add_library(pybind11::opt_size IMPORTED INTERFACE ${optional_global})
|
125 |
+
|
126 |
+
if(MSVC)
|
127 |
+
set(PYBIND11_OPT_SIZE /Os)
|
128 |
+
else()
|
129 |
+
set(PYBIND11_OPT_SIZE -Os)
|
130 |
+
endif()
|
131 |
+
|
132 |
+
set_property(
|
133 |
+
TARGET pybind11::opt_size
|
134 |
+
APPEND
|
135 |
+
PROPERTY INTERFACE_COMPILE_OPTIONS $<$<CONFIG:Release>:${PYBIND11_OPT_SIZE}>
|
136 |
+
$<$<CONFIG:MinSizeRel>:${PYBIND11_OPT_SIZE}>
|
137 |
+
$<$<CONFIG:RelWithDebInfo>:${PYBIND11_OPT_SIZE}>)
|
138 |
+
|
139 |
+
# ----------------------- Legacy option --------------------------
|
140 |
+
|
141 |
+
# Warn or error if old variable name used
|
142 |
+
if(PYBIND11_CPP_STANDARD)
|
143 |
+
string(REGEX MATCH [[..$]] VAL "${PYBIND11_CPP_STANDARD}")
|
144 |
+
if(CMAKE_CXX_STANDARD)
|
145 |
+
if(NOT CMAKE_CXX_STANDARD STREQUAL VAL)
|
146 |
+
message(WARNING "CMAKE_CXX_STANDARD=${CMAKE_CXX_STANDARD} does not match "
|
147 |
+
"PYBIND11_CPP_STANDARD=${PYBIND11_CPP_STANDARD}, "
|
148 |
+
"please remove PYBIND11_CPP_STANDARD from your cache")
|
149 |
+
endif()
|
150 |
+
else()
|
151 |
+
set(supported_standards 11 14 17 20)
|
152 |
+
if("${VAL}" IN_LIST supported_standards)
|
153 |
+
message(WARNING "USE -DCMAKE_CXX_STANDARD=${VAL} instead of PYBIND11_CPP_STANDARD")
|
154 |
+
set(CMAKE_CXX_STANDARD
|
155 |
+
${VAL}
|
156 |
+
CACHE STRING "From PYBIND11_CPP_STANDARD")
|
157 |
+
else()
|
158 |
+
message(FATAL_ERROR "PYBIND11_CPP_STANDARD should be replaced with CMAKE_CXX_STANDARD "
|
159 |
+
"(last two chars: ${VAL} not understood as a valid CXX std)")
|
160 |
+
endif()
|
161 |
+
endif()
|
162 |
+
endif()
|
163 |
+
|
164 |
+
# --------------------- Python specifics -------------------------
|
165 |
+
|
166 |
+
# Check to see which Python mode we are in, new, old, or no python
|
167 |
+
if(PYBIND11_NOPYTHON)
|
168 |
+
set(_pybind11_nopython ON)
|
169 |
+
elseif(
|
170 |
+
PYBIND11_FINDPYTHON
|
171 |
+
OR Python_FOUND
|
172 |
+
OR Python2_FOUND
|
173 |
+
OR Python3_FOUND)
|
174 |
+
# New mode
|
175 |
+
include("${CMAKE_CURRENT_LIST_DIR}/pybind11NewTools.cmake")
|
176 |
+
|
177 |
+
else()
|
178 |
+
|
179 |
+
# Classic mode
|
180 |
+
include("${CMAKE_CURRENT_LIST_DIR}/pybind11Tools.cmake")
|
181 |
+
|
182 |
+
endif()
|
183 |
+
|
184 |
+
# --------------------- pybind11_find_import -------------------------------
|
185 |
+
|
186 |
+
if(NOT _pybind11_nopython)
|
187 |
+
# Check to see if modules are importable. Use REQUIRED to force an error if
|
188 |
+
# one of the modules is not found. <package_name>_FOUND will be set if the
|
189 |
+
# package was found (underscores replace dashes if present). QUIET will hide
|
190 |
+
# the found message, and VERSION will require a minimum version. A successful
|
191 |
+
# find will cache the result.
|
192 |
+
function(pybind11_find_import PYPI_NAME)
|
193 |
+
# CMake variables need underscores (PyPI doesn't care)
|
194 |
+
string(REPLACE "-" "_" NORM_PYPI_NAME "${PYPI_NAME}")
|
195 |
+
|
196 |
+
# Return if found previously
|
197 |
+
if(${NORM_PYPI_NAME}_FOUND)
|
198 |
+
return()
|
199 |
+
endif()
|
200 |
+
|
201 |
+
set(options "REQUIRED;QUIET")
|
202 |
+
set(oneValueArgs "VERSION")
|
203 |
+
cmake_parse_arguments(ARG "${options}" "${oneValueArgs}" "" ${ARGN})
|
204 |
+
|
205 |
+
if(ARG_REQUIRED)
|
206 |
+
set(status_level FATAL_ERROR)
|
207 |
+
else()
|
208 |
+
set(status_level WARNING)
|
209 |
+
endif()
|
210 |
+
|
211 |
+
execute_process(
|
212 |
+
COMMAND
|
213 |
+
${${_Python}_EXECUTABLE} -c
|
214 |
+
"from pkg_resources import get_distribution; print(get_distribution('${PYPI_NAME}').version)"
|
215 |
+
RESULT_VARIABLE RESULT_PRESENT
|
216 |
+
OUTPUT_VARIABLE PKG_VERSION
|
217 |
+
ERROR_QUIET)
|
218 |
+
|
219 |
+
string(STRIP "${PKG_VERSION}" PKG_VERSION)
|
220 |
+
|
221 |
+
# If a result is present, this failed
|
222 |
+
if(RESULT_PRESENT)
|
223 |
+
set(${NORM_PYPI_NAME}_FOUND
|
224 |
+
${NORM_PYPI_NAME}-NOTFOUND
|
225 |
+
CACHE INTERNAL "")
|
226 |
+
# Always warn or error
|
227 |
+
message(
|
228 |
+
${status_level}
|
229 |
+
"Missing: ${PYPI_NAME} ${ARG_VERSION}\nTry: ${${_Python}_EXECUTABLE} -m pip install ${PYPI_NAME}"
|
230 |
+
)
|
231 |
+
else()
|
232 |
+
if(ARG_VERSION AND PKG_VERSION VERSION_LESS ARG_VERSION)
|
233 |
+
message(
|
234 |
+
${status_level}
|
235 |
+
"Version incorrect: ${PYPI_NAME} ${PKG_VERSION} found, ${ARG_VERSION} required - try upgrading"
|
236 |
+
)
|
237 |
+
else()
|
238 |
+
set(${NORM_PYPI_NAME}_FOUND
|
239 |
+
YES
|
240 |
+
CACHE INTERNAL "")
|
241 |
+
set(${NORM_PYPI_NAME}_VERSION
|
242 |
+
${PKG_VERSION}
|
243 |
+
CACHE INTERNAL "")
|
244 |
+
endif()
|
245 |
+
if(NOT ARG_QUIET)
|
246 |
+
message(STATUS "Found ${PYPI_NAME} ${PKG_VERSION}")
|
247 |
+
endif()
|
248 |
+
endif()
|
249 |
+
if(NOT ARG_VERSION OR (NOT PKG_VERSION VERSION_LESS ARG_VERSION))
|
250 |
+
# We have successfully found a good version, cache to avoid calling again.
|
251 |
+
endif()
|
252 |
+
endfunction()
|
253 |
+
endif()
|
254 |
+
|
255 |
+
# --------------------- LTO -------------------------------
|
256 |
+
|
257 |
+
include(CheckCXXCompilerFlag)
|
258 |
+
|
259 |
+
# Checks whether the given CXX/linker flags can compile and link a cxx file.
|
260 |
+
# cxxflags and linkerflags are lists of flags to use. The result variable is a
|
261 |
+
# unique variable name for each set of flags: the compilation result will be
|
262 |
+
# cached base on the result variable. If the flags work, sets them in
|
263 |
+
# cxxflags_out/linkerflags_out internal cache variables (in addition to
|
264 |
+
# ${result}).
|
265 |
+
function(_pybind11_return_if_cxx_and_linker_flags_work result cxxflags linkerflags cxxflags_out
|
266 |
+
linkerflags_out)
|
267 |
+
set(CMAKE_REQUIRED_LIBRARIES ${linkerflags})
|
268 |
+
check_cxx_compiler_flag("${cxxflags}" ${result})
|
269 |
+
if(${result})
|
270 |
+
set(${cxxflags_out}
|
271 |
+
"${cxxflags}"
|
272 |
+
PARENT_SCOPE)
|
273 |
+
set(${linkerflags_out}
|
274 |
+
"${linkerflags}"
|
275 |
+
PARENT_SCOPE)
|
276 |
+
endif()
|
277 |
+
endfunction()
|
278 |
+
|
279 |
+
function(_pybind11_generate_lto target prefer_thin_lto)
|
280 |
+
if(MINGW)
|
281 |
+
message(STATUS "${target} disabled (problems with undefined symbols for MinGW for now)")
|
282 |
+
return()
|
283 |
+
endif()
|
284 |
+
|
285 |
+
if(CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang")
|
286 |
+
set(cxx_append "")
|
287 |
+
set(linker_append "")
|
288 |
+
if(CMAKE_CXX_COMPILER_ID MATCHES "Clang" AND NOT APPLE)
|
289 |
+
# Clang Gold plugin does not support -Os; append -O3 to MinSizeRel builds to override it
|
290 |
+
set(linker_append ";$<$<CONFIG:MinSizeRel>:-O3>")
|
291 |
+
elseif(CMAKE_CXX_COMPILER_ID MATCHES "GNU" AND NOT MINGW)
|
292 |
+
set(cxx_append ";-fno-fat-lto-objects")
|
293 |
+
endif()
|
294 |
+
|
295 |
+
if(CMAKE_SYSTEM_PROCESSOR MATCHES "ppc64le" OR CMAKE_SYSTEM_PROCESSOR MATCHES "mips64")
|
296 |
+
set(NO_FLTO_ARCH TRUE)
|
297 |
+
else()
|
298 |
+
set(NO_FLTO_ARCH FALSE)
|
299 |
+
endif()
|
300 |
+
|
301 |
+
if(CMAKE_CXX_COMPILER_ID MATCHES "Clang"
|
302 |
+
AND prefer_thin_lto
|
303 |
+
AND NOT NO_FLTO_ARCH)
|
304 |
+
_pybind11_return_if_cxx_and_linker_flags_work(
|
305 |
+
HAS_FLTO_THIN "-flto=thin${cxx_append}" "-flto=thin${linker_append}"
|
306 |
+
PYBIND11_LTO_CXX_FLAGS PYBIND11_LTO_LINKER_FLAGS)
|
307 |
+
endif()
|
308 |
+
|
309 |
+
if(NOT HAS_FLTO_THIN AND NOT NO_FLTO_ARCH)
|
310 |
+
_pybind11_return_if_cxx_and_linker_flags_work(
|
311 |
+
HAS_FLTO "-flto${cxx_append}" "-flto${linker_append}" PYBIND11_LTO_CXX_FLAGS
|
312 |
+
PYBIND11_LTO_LINKER_FLAGS)
|
313 |
+
endif()
|
314 |
+
elseif(CMAKE_CXX_COMPILER_ID MATCHES "Intel")
|
315 |
+
# Intel equivalent to LTO is called IPO
|
316 |
+
_pybind11_return_if_cxx_and_linker_flags_work(HAS_INTEL_IPO "-ipo" "-ipo"
|
317 |
+
PYBIND11_LTO_CXX_FLAGS PYBIND11_LTO_LINKER_FLAGS)
|
318 |
+
elseif(MSVC)
|
319 |
+
# cmake only interprets libraries as linker flags when they start with a - (otherwise it
|
320 |
+
# converts /LTCG to \LTCG as if it was a Windows path). Luckily MSVC supports passing flags
|
321 |
+
# with - instead of /, even if it is a bit non-standard:
|
322 |
+
_pybind11_return_if_cxx_and_linker_flags_work(HAS_MSVC_GL_LTCG "/GL" "-LTCG"
|
323 |
+
PYBIND11_LTO_CXX_FLAGS PYBIND11_LTO_LINKER_FLAGS)
|
324 |
+
endif()
|
325 |
+
|
326 |
+
# Enable LTO flags if found, except for Debug builds
|
327 |
+
if(PYBIND11_LTO_CXX_FLAGS)
|
328 |
+
# CONFIG takes multiple values in CMake 3.19+, until then we have to use OR
|
329 |
+
set(is_debug "$<OR:$<CONFIG:Debug>,$<CONFIG:RelWithDebInfo>>")
|
330 |
+
set(not_debug "$<NOT:${is_debug}>")
|
331 |
+
set(cxx_lang "$<COMPILE_LANGUAGE:CXX>")
|
332 |
+
if(MSVC AND CMAKE_VERSION VERSION_LESS 3.11)
|
333 |
+
set(genex "${not_debug}")
|
334 |
+
else()
|
335 |
+
set(genex "$<AND:${not_debug},${cxx_lang}>")
|
336 |
+
endif()
|
337 |
+
set_property(
|
338 |
+
TARGET ${target}
|
339 |
+
APPEND
|
340 |
+
PROPERTY INTERFACE_COMPILE_OPTIONS "$<${genex}:${PYBIND11_LTO_CXX_FLAGS}>")
|
341 |
+
if(CMAKE_PROJECT_NAME STREQUAL "pybind11")
|
342 |
+
message(STATUS "${target} enabled")
|
343 |
+
endif()
|
344 |
+
else()
|
345 |
+
if(CMAKE_PROJECT_NAME STREQUAL "pybind11")
|
346 |
+
message(STATUS "${target} disabled (not supported by the compiler and/or linker)")
|
347 |
+
endif()
|
348 |
+
endif()
|
349 |
+
|
350 |
+
if(PYBIND11_LTO_LINKER_FLAGS)
|
351 |
+
if(CMAKE_VERSION VERSION_LESS 3.11)
|
352 |
+
set_property(
|
353 |
+
TARGET ${target}
|
354 |
+
APPEND
|
355 |
+
PROPERTY INTERFACE_LINK_LIBRARIES "$<${not_debug}:${PYBIND11_LTO_LINKER_FLAGS}>")
|
356 |
+
else()
|
357 |
+
set_property(
|
358 |
+
TARGET ${target}
|
359 |
+
APPEND
|
360 |
+
PROPERTY INTERFACE_LINK_OPTIONS "$<${not_debug}:${PYBIND11_LTO_LINKER_FLAGS}>")
|
361 |
+
endif()
|
362 |
+
endif()
|
363 |
+
endfunction()
|
364 |
+
|
365 |
+
add_library(pybind11::lto IMPORTED INTERFACE ${optional_global})
|
366 |
+
_pybind11_generate_lto(pybind11::lto FALSE)
|
367 |
+
|
368 |
+
add_library(pybind11::thin_lto IMPORTED INTERFACE ${optional_global})
|
369 |
+
_pybind11_generate_lto(pybind11::thin_lto TRUE)
|
370 |
+
|
371 |
+
# ---------------------- pybind11_strip -----------------------------
|
372 |
+
|
373 |
+
function(pybind11_strip target_name)
|
374 |
+
# Strip unnecessary sections of the binary on Linux/macOS
|
375 |
+
if(CMAKE_STRIP)
|
376 |
+
if(APPLE)
|
377 |
+
set(x_opt -x)
|
378 |
+
endif()
|
379 |
+
|
380 |
+
add_custom_command(
|
381 |
+
TARGET ${target_name}
|
382 |
+
POST_BUILD
|
383 |
+
COMMAND ${CMAKE_STRIP} ${x_opt} $<TARGET_FILE:${target_name}>)
|
384 |
+
endif()
|
385 |
+
endfunction()
|
third-party/DPVO/DPViewer/pybind11/tools/pybind11Config.cmake.in
ADDED
@@ -0,0 +1,231 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
#[=============================================================================[.rst:
|
2 |
+
|
3 |
+
pybind11Config.cmake
|
4 |
+
####################
|
5 |
+
|
6 |
+
Exported variables
|
7 |
+
==================
|
8 |
+
|
9 |
+
This module sets the following variables in your project:
|
10 |
+
|
11 |
+
``pybind11_FOUND``
|
12 |
+
true if pybind11 and all required components found on the system
|
13 |
+
``pybind11_VERSION``
|
14 |
+
pybind11 version in format Major.Minor.Release
|
15 |
+
``pybind11_VERSION_TYPE``
|
16 |
+
pybind11 version type (``dev*`` or empty for a release)
|
17 |
+
``pybind11_INCLUDE_DIRS``
|
18 |
+
Directories where pybind11 and python headers are located.
|
19 |
+
``pybind11_INCLUDE_DIR``
|
20 |
+
Directory where pybind11 headers are located.
|
21 |
+
``pybind11_DEFINITIONS``
|
22 |
+
Definitions necessary to use pybind11, namely USING_pybind11.
|
23 |
+
``pybind11_LIBRARIES``
|
24 |
+
Compile flags and python libraries (as needed) to link against.
|
25 |
+
``pybind11_LIBRARY``
|
26 |
+
Empty.
|
27 |
+
|
28 |
+
Available components: None
|
29 |
+
|
30 |
+
|
31 |
+
Exported targets
|
32 |
+
================
|
33 |
+
|
34 |
+
If pybind11 is found, this module defines the following ``IMPORTED``
|
35 |
+
interface library targets:
|
36 |
+
|
37 |
+
``pybind11::module``
|
38 |
+
for extension modules.
|
39 |
+
``pybind11::embed``
|
40 |
+
for embedding the Python interpreter.
|
41 |
+
|
42 |
+
Python headers, libraries (as needed by platform), and the C++ standard
|
43 |
+
are attached to the target.
|
44 |
+
|
45 |
+
Advanced targets are also supplied - these are primary for users building
|
46 |
+
complex applications, and they are available in all modes:
|
47 |
+
|
48 |
+
``pybind11::headers``
|
49 |
+
Just the pybind11 headers and minimum compile requirements.
|
50 |
+
``pybind11::pybind11``
|
51 |
+
Python headers too.
|
52 |
+
``pybind11::python_link_helper``
|
53 |
+
Just the "linking" part of ``pybind11:module``, for CMake < 3.15.
|
54 |
+
``pybind11::thin_lto``
|
55 |
+
An alternative to ``INTERPROCEDURAL_OPTIMIZATION``.
|
56 |
+
``pybind11::lto``
|
57 |
+
An alternative to ``INTERPROCEDURAL_OPTIMIZATION`` (also avoids thin LTO on clang).
|
58 |
+
``pybind11::windows_extras``
|
59 |
+
Adds bigobj and mp for MSVC.
|
60 |
+
|
61 |
+
Modes
|
62 |
+
=====
|
63 |
+
|
64 |
+
There are two modes provided; classic, which is built on the old Python
|
65 |
+
discovery packages in CMake, or the new FindPython mode, which uses FindPython
|
66 |
+
from 3.12+ forward (3.15+ _highly_ recommended).
|
67 |
+
|
68 |
+
New FindPython mode
|
69 |
+
^^^^^^^^^^^^^^^^^^^
|
70 |
+
|
71 |
+
To activate this mode, either call ``find_package(Python COMPONENTS Interpreter Development)``
|
72 |
+
before finding this package, or set the ``PYBIND11_FINDPYTHON`` variable to ON. In this mode,
|
73 |
+
you can either use the basic targets, or use the FindPython tools:
|
74 |
+
|
75 |
+
.. code-block:: cmake
|
76 |
+
|
77 |
+
find_package(Python COMPONENTS Interpreter Development)
|
78 |
+
find_package(pybind11 CONFIG)
|
79 |
+
|
80 |
+
# pybind11 method:
|
81 |
+
pybind11_add_module(MyModule1 src1.cpp)
|
82 |
+
|
83 |
+
# Python method:
|
84 |
+
Python_add_library(MyModule2 src2.cpp)
|
85 |
+
target_link_libraries(MyModule2 pybind11::headers)
|
86 |
+
set_target_properties(MyModule2 PROPERTIES
|
87 |
+
INTERPROCEDURAL_OPTIMIZATION ON
|
88 |
+
CXX_VISIBILITY_PRESET ON
|
89 |
+
VISIBILITY_INLINES_HIDDEN ON)
|
90 |
+
|
91 |
+
If you build targets yourself, you may be interested in stripping the output
|
92 |
+
for reduced size; this is the one other feature that the helper function gives you.
|
93 |
+
|
94 |
+
Classic mode
|
95 |
+
^^^^^^^^^^^^
|
96 |
+
|
97 |
+
Set PythonLibsNew variables to influence python detection and
|
98 |
+
CMAKE_CXX_STANDARD to influence standard setting.
|
99 |
+
|
100 |
+
.. code-block:: cmake
|
101 |
+
|
102 |
+
find_package(pybind11 CONFIG REQUIRED)
|
103 |
+
|
104 |
+
# Create an extension module
|
105 |
+
add_library(mylib MODULE main.cpp)
|
106 |
+
target_link_libraries(mylib PUBLIC pybind11::module)
|
107 |
+
|
108 |
+
# Or embed the Python interpreter into an executable
|
109 |
+
add_executable(myexe main.cpp)
|
110 |
+
target_link_libraries(myexe PUBLIC pybind11::embed)
|
111 |
+
|
112 |
+
|
113 |
+
Hints
|
114 |
+
=====
|
115 |
+
|
116 |
+
The following variables can be set to guide the search for this package:
|
117 |
+
|
118 |
+
``pybind11_DIR``
|
119 |
+
CMake variable, set to directory containing this Config file.
|
120 |
+
``CMAKE_PREFIX_PATH``
|
121 |
+
CMake variable, set to root directory of this package.
|
122 |
+
``PATH``
|
123 |
+
Environment variable, set to bin directory of this package.
|
124 |
+
``CMAKE_DISABLE_FIND_PACKAGE_pybind11``
|
125 |
+
CMake variable, disables ``find_package(pybind11)`` when not ``REQUIRED``,
|
126 |
+
perhaps to force internal build.
|
127 |
+
|
128 |
+
Commands
|
129 |
+
========
|
130 |
+
|
131 |
+
pybind11_add_module
|
132 |
+
^^^^^^^^^^^^^^^^^^^
|
133 |
+
|
134 |
+
This module defines the following commands to assist with creating Python modules:
|
135 |
+
|
136 |
+
.. code-block:: cmake
|
137 |
+
|
138 |
+
pybind11_add_module(<target>
|
139 |
+
[STATIC|SHARED|MODULE]
|
140 |
+
[THIN_LTO] [OPT_SIZE] [NO_EXTRAS] [WITHOUT_SOABI]
|
141 |
+
<files>...
|
142 |
+
)
|
143 |
+
|
144 |
+
Add a module and setup all helpers. You can select the type of the library; the
|
145 |
+
default is ``MODULE``. There are several options:
|
146 |
+
|
147 |
+
``OPT_SIZE``
|
148 |
+
Optimize for size, even if the ``CMAKE_BUILD_TYPE`` is not ``MinSizeRel``.
|
149 |
+
``THIN_LTO``
|
150 |
+
Use thin TLO instead of regular if there's a choice (pybind11's selection
|
151 |
+
is disabled if ``CMAKE_INTERPROCEDURAL_OPTIMIZATIONS`` is set).
|
152 |
+
``WITHOUT_SOABI``
|
153 |
+
Disable the SOABI component (``PYBIND11_NEWPYTHON`` mode only).
|
154 |
+
``NO_EXTRAS``
|
155 |
+
Disable all extras, exit immediately after making the module.
|
156 |
+
|
157 |
+
pybind11_strip
|
158 |
+
^^^^^^^^^^^^^^
|
159 |
+
|
160 |
+
.. code-block:: cmake
|
161 |
+
|
162 |
+
pybind11_strip(<target>)
|
163 |
+
|
164 |
+
Strip a target after building it (linux/macOS), called by ``pybind11_add_module``.
|
165 |
+
|
166 |
+
pybind11_extension
|
167 |
+
^^^^^^^^^^^^^^^^^^
|
168 |
+
|
169 |
+
.. code-block:: cmake
|
170 |
+
|
171 |
+
pybind11_extension(<target>)
|
172 |
+
|
173 |
+
Sets the Python extension name correctly for Python on your platform, called by
|
174 |
+
``pybind11_add_module``.
|
175 |
+
|
176 |
+
pybind11_find_import(module)
|
177 |
+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
178 |
+
|
179 |
+
.. code-block:: cmake
|
180 |
+
|
181 |
+
pybind11_find_import(<module> [VERSION <number>] [REQUIRED] [QUIET])
|
182 |
+
|
183 |
+
See if a module is installed. Use the registered name (the one on PyPI). You
|
184 |
+
can specify a ``VERSION``, and you can specify ``REQUIRED`` or ``QUIET``. Only available if
|
185 |
+
``NOPYTHON`` mode is not active. Sets ``module_VERSION`` and ``module_FOUND``. Caches the
|
186 |
+
result once a valid install is found.
|
187 |
+
|
188 |
+
Suggested usage
|
189 |
+
===============
|
190 |
+
|
191 |
+
Using ``find_package`` with version info is not recommended except for release versions.
|
192 |
+
|
193 |
+
.. code-block:: cmake
|
194 |
+
|
195 |
+
find_package(pybind11 CONFIG)
|
196 |
+
find_package(pybind11 2.9 EXACT CONFIG REQUIRED)
|
197 |
+
|
198 |
+
#]=============================================================================]
|
199 |
+
@PACKAGE_INIT@
|
200 |
+
|
201 |
+
# Location of pybind11/pybind11.h
|
202 |
+
# This will be relative unless explicitly set as absolute
|
203 |
+
set(pybind11_INCLUDE_DIR "@pybind11_INCLUDEDIR@")
|
204 |
+
|
205 |
+
set(pybind11_LIBRARY "")
|
206 |
+
set(pybind11_DEFINITIONS USING_pybind11)
|
207 |
+
set(pybind11_VERSION_TYPE "@pybind11_VERSION_TYPE@")
|
208 |
+
|
209 |
+
check_required_components(pybind11)
|
210 |
+
|
211 |
+
if(TARGET pybind11::python_link_helper)
|
212 |
+
# This has already been setup elsewhere, such as with a previous call or
|
213 |
+
# add_subdirectory
|
214 |
+
return()
|
215 |
+
endif()
|
216 |
+
|
217 |
+
include("${CMAKE_CURRENT_LIST_DIR}/pybind11Targets.cmake")
|
218 |
+
|
219 |
+
# Easier to use / remember
|
220 |
+
add_library(pybind11::headers IMPORTED INTERFACE)
|
221 |
+
set_target_properties(pybind11::headers PROPERTIES INTERFACE_LINK_LIBRARIES
|
222 |
+
pybind11::pybind11_headers)
|
223 |
+
|
224 |
+
include("${CMAKE_CURRENT_LIST_DIR}/pybind11Common.cmake")
|
225 |
+
|
226 |
+
if(NOT pybind11_FIND_QUIETLY)
|
227 |
+
message(
|
228 |
+
STATUS
|
229 |
+
"Found pybind11: ${pybind11_INCLUDE_DIR} (found version \"${pybind11_VERSION}${pybind11_VERSION_TYPE}\")"
|
230 |
+
)
|
231 |
+
endif()
|
third-party/DPVO/DPViewer/pybind11/tools/pybind11NewTools.cmake
ADDED
@@ -0,0 +1,254 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# tools/pybind11NewTools.cmake -- Build system for the pybind11 modules
|
2 |
+
#
|
3 |
+
# Copyright (c) 2020 Wenzel Jakob <[email protected]> and Henry Schreiner
|
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 |
+
if(CMAKE_VERSION VERSION_LESS 3.12)
|
9 |
+
message(FATAL_ERROR "You cannot use the new FindPython module with CMake < 3.12")
|
10 |
+
endif()
|
11 |
+
|
12 |
+
include_guard(GLOBAL)
|
13 |
+
|
14 |
+
get_property(
|
15 |
+
is_config
|
16 |
+
TARGET pybind11::headers
|
17 |
+
PROPERTY IMPORTED)
|
18 |
+
|
19 |
+
if(pybind11_FIND_QUIETLY)
|
20 |
+
set(_pybind11_quiet QUIET)
|
21 |
+
else()
|
22 |
+
set(_pybind11_quiet "")
|
23 |
+
endif()
|
24 |
+
|
25 |
+
if(NOT Python_FOUND AND NOT Python3_FOUND)
|
26 |
+
if(NOT DEFINED Python_FIND_IMPLEMENTATIONS)
|
27 |
+
set(Python_FIND_IMPLEMENTATIONS CPython PyPy)
|
28 |
+
endif()
|
29 |
+
|
30 |
+
# GitHub Actions like activation
|
31 |
+
if(NOT DEFINED Python_ROOT_DIR AND DEFINED ENV{pythonLocation})
|
32 |
+
set(Python_ROOT_DIR "$ENV{pythonLocation}")
|
33 |
+
endif()
|
34 |
+
|
35 |
+
find_package(Python 3.6 REQUIRED COMPONENTS Interpreter Development ${_pybind11_quiet})
|
36 |
+
|
37 |
+
# If we are in submodule mode, export the Python targets to global targets.
|
38 |
+
# If this behavior is not desired, FindPython _before_ pybind11.
|
39 |
+
if(NOT is_config)
|
40 |
+
set_property(TARGET Python::Python PROPERTY IMPORTED_GLOBAL TRUE)
|
41 |
+
set_property(TARGET Python::Interpreter PROPERTY IMPORTED_GLOBAL TRUE)
|
42 |
+
if(TARGET Python::Module)
|
43 |
+
set_property(TARGET Python::Module PROPERTY IMPORTED_GLOBAL TRUE)
|
44 |
+
endif()
|
45 |
+
endif()
|
46 |
+
endif()
|
47 |
+
|
48 |
+
if(Python_FOUND)
|
49 |
+
set(_Python
|
50 |
+
Python
|
51 |
+
CACHE INTERNAL "" FORCE)
|
52 |
+
elseif(Python3_FOUND)
|
53 |
+
set(_Python
|
54 |
+
Python3
|
55 |
+
CACHE INTERNAL "" FORCE)
|
56 |
+
endif()
|
57 |
+
|
58 |
+
if(PYBIND11_MASTER_PROJECT)
|
59 |
+
if(${_Python}_INTERPRETER_ID MATCHES "PyPy")
|
60 |
+
message(STATUS "PyPy ${${_Python}_PyPy_VERSION} (Py ${${_Python}_VERSION})")
|
61 |
+
else()
|
62 |
+
message(STATUS "${_Python} ${${_Python}_VERSION}")
|
63 |
+
endif()
|
64 |
+
endif()
|
65 |
+
|
66 |
+
# If a user finds Python, they may forget to include the Interpreter component
|
67 |
+
# and the following two steps require it. It is highly recommended by CMake
|
68 |
+
# when finding development libraries anyway, so we will require it.
|
69 |
+
if(NOT DEFINED ${_Python}_EXECUTABLE)
|
70 |
+
message(
|
71 |
+
FATAL_ERROR
|
72 |
+
"${_Python} was found without the Interpreter component. Pybind11 requires this component.")
|
73 |
+
|
74 |
+
endif()
|
75 |
+
|
76 |
+
if(NOT ${_Python}_EXECUTABLE STREQUAL PYBIND11_PYTHON_EXECUTABLE_LAST)
|
77 |
+
# Detect changes to the Python version/binary in subsequent CMake runs, and refresh config if needed
|
78 |
+
unset(PYTHON_IS_DEBUG CACHE)
|
79 |
+
unset(PYTHON_MODULE_EXTENSION CACHE)
|
80 |
+
set(PYBIND11_PYTHON_EXECUTABLE_LAST
|
81 |
+
"${${_Python}_EXECUTABLE}"
|
82 |
+
CACHE INTERNAL "Python executable during the last CMake run")
|
83 |
+
endif()
|
84 |
+
|
85 |
+
if(NOT DEFINED PYTHON_IS_DEBUG)
|
86 |
+
# Debug check - see https://stackoverflow.com/questions/646518/python-how-to-detect-debug-Interpreter
|
87 |
+
execute_process(
|
88 |
+
COMMAND "${${_Python}_EXECUTABLE}" "-c"
|
89 |
+
"import sys; sys.exit(hasattr(sys, 'gettotalrefcount'))"
|
90 |
+
RESULT_VARIABLE _PYTHON_IS_DEBUG)
|
91 |
+
set(PYTHON_IS_DEBUG
|
92 |
+
"${_PYTHON_IS_DEBUG}"
|
93 |
+
CACHE INTERNAL "Python debug status")
|
94 |
+
endif()
|
95 |
+
|
96 |
+
# Get the suffix - SO is deprecated, should use EXT_SUFFIX, but this is
|
97 |
+
# required for PyPy3 (as of 7.3.1)
|
98 |
+
if(NOT DEFINED PYTHON_MODULE_EXTENSION)
|
99 |
+
execute_process(
|
100 |
+
COMMAND
|
101 |
+
"${${_Python}_EXECUTABLE}" "-c"
|
102 |
+
"import sys, importlib; s = importlib.import_module('distutils.sysconfig' if sys.version_info < (3, 10) else 'sysconfig'); print(s.get_config_var('EXT_SUFFIX') or s.get_config_var('SO'))"
|
103 |
+
OUTPUT_VARIABLE _PYTHON_MODULE_EXTENSION
|
104 |
+
ERROR_VARIABLE _PYTHON_MODULE_EXTENSION_ERR
|
105 |
+
OUTPUT_STRIP_TRAILING_WHITESPACE)
|
106 |
+
|
107 |
+
if(_PYTHON_MODULE_EXTENSION STREQUAL "")
|
108 |
+
message(
|
109 |
+
FATAL_ERROR "pybind11 could not query the module file extension, likely the 'distutils'"
|
110 |
+
"package is not installed. Full error message:\n${_PYTHON_MODULE_EXTENSION_ERR}")
|
111 |
+
endif()
|
112 |
+
|
113 |
+
# This needs to be available for the pybind11_extension function
|
114 |
+
set(PYTHON_MODULE_EXTENSION
|
115 |
+
"${_PYTHON_MODULE_EXTENSION}"
|
116 |
+
CACHE INTERNAL "")
|
117 |
+
endif()
|
118 |
+
|
119 |
+
# Python debug libraries expose slightly different objects before 3.8
|
120 |
+
# https://docs.python.org/3.6/c-api/intro.html#debugging-builds
|
121 |
+
# https://stackoverflow.com/questions/39161202/how-to-work-around-missing-pymodule-create2-in-amd64-win-python35-d-lib
|
122 |
+
if(PYTHON_IS_DEBUG)
|
123 |
+
set_property(
|
124 |
+
TARGET pybind11::pybind11
|
125 |
+
APPEND
|
126 |
+
PROPERTY INTERFACE_COMPILE_DEFINITIONS Py_DEBUG)
|
127 |
+
endif()
|
128 |
+
|
129 |
+
# Check on every access - since Python can change - do nothing in that case.
|
130 |
+
|
131 |
+
if(DEFINED ${_Python}_INCLUDE_DIRS)
|
132 |
+
# Only add Python for build - must be added during the import for config
|
133 |
+
# since it has to be re-discovered.
|
134 |
+
#
|
135 |
+
# This needs to be a target to be included after the local pybind11
|
136 |
+
# directory, just in case there there is an installed pybind11 sitting
|
137 |
+
# next to Python's includes. It also ensures Python is a SYSTEM library.
|
138 |
+
add_library(pybind11::python_headers INTERFACE IMPORTED)
|
139 |
+
set_property(
|
140 |
+
TARGET pybind11::python_headers PROPERTY INTERFACE_INCLUDE_DIRECTORIES
|
141 |
+
"$<BUILD_INTERFACE:${${_Python}_INCLUDE_DIRS}>")
|
142 |
+
set_property(
|
143 |
+
TARGET pybind11::pybind11
|
144 |
+
APPEND
|
145 |
+
PROPERTY INTERFACE_LINK_LIBRARIES pybind11::python_headers)
|
146 |
+
set(pybind11_INCLUDE_DIRS
|
147 |
+
"${pybind11_INCLUDE_DIR}" "${${_Python}_INCLUDE_DIRS}"
|
148 |
+
CACHE INTERNAL "Directories where pybind11 and possibly Python headers are located")
|
149 |
+
endif()
|
150 |
+
|
151 |
+
# In CMake 3.18+, you can find these separately, so include an if
|
152 |
+
if(TARGET ${_Python}::Python)
|
153 |
+
set_property(
|
154 |
+
TARGET pybind11::embed
|
155 |
+
APPEND
|
156 |
+
PROPERTY INTERFACE_LINK_LIBRARIES ${_Python}::Python)
|
157 |
+
endif()
|
158 |
+
|
159 |
+
# CMake 3.15+ has this
|
160 |
+
if(TARGET ${_Python}::Module)
|
161 |
+
set_property(
|
162 |
+
TARGET pybind11::module
|
163 |
+
APPEND
|
164 |
+
PROPERTY INTERFACE_LINK_LIBRARIES ${_Python}::Module)
|
165 |
+
else()
|
166 |
+
set_property(
|
167 |
+
TARGET pybind11::module
|
168 |
+
APPEND
|
169 |
+
PROPERTY INTERFACE_LINK_LIBRARIES pybind11::python_link_helper)
|
170 |
+
endif()
|
171 |
+
|
172 |
+
# WITHOUT_SOABI and WITH_SOABI will disable the custom extension handling used by pybind11.
|
173 |
+
# WITH_SOABI is passed on to python_add_library.
|
174 |
+
function(pybind11_add_module target_name)
|
175 |
+
cmake_parse_arguments(PARSE_ARGV 1 ARG
|
176 |
+
"STATIC;SHARED;MODULE;THIN_LTO;OPT_SIZE;NO_EXTRAS;WITHOUT_SOABI" "" "")
|
177 |
+
|
178 |
+
if(ARG_STATIC)
|
179 |
+
set(lib_type STATIC)
|
180 |
+
elseif(ARG_SHARED)
|
181 |
+
set(lib_type SHARED)
|
182 |
+
else()
|
183 |
+
set(lib_type MODULE)
|
184 |
+
endif()
|
185 |
+
|
186 |
+
if("${_Python}" STREQUAL "Python")
|
187 |
+
python_add_library(${target_name} ${lib_type} ${ARG_UNPARSED_ARGUMENTS})
|
188 |
+
elseif("${_Python}" STREQUAL "Python3")
|
189 |
+
python3_add_library(${target_name} ${lib_type} ${ARG_UNPARSED_ARGUMENTS})
|
190 |
+
else()
|
191 |
+
message(FATAL_ERROR "Cannot detect FindPython version: ${_Python}")
|
192 |
+
endif()
|
193 |
+
|
194 |
+
target_link_libraries(${target_name} PRIVATE pybind11::headers)
|
195 |
+
|
196 |
+
if(lib_type STREQUAL "MODULE")
|
197 |
+
target_link_libraries(${target_name} PRIVATE pybind11::module)
|
198 |
+
else()
|
199 |
+
target_link_libraries(${target_name} PRIVATE pybind11::embed)
|
200 |
+
endif()
|
201 |
+
|
202 |
+
if(MSVC)
|
203 |
+
target_link_libraries(${target_name} PRIVATE pybind11::windows_extras)
|
204 |
+
endif()
|
205 |
+
|
206 |
+
# -fvisibility=hidden is required to allow multiple modules compiled against
|
207 |
+
# different pybind versions to work properly, and for some features (e.g.
|
208 |
+
# py::module_local). We force it on everything inside the `pybind11`
|
209 |
+
# namespace; also turning it on for a pybind module compilation here avoids
|
210 |
+
# potential warnings or issues from having mixed hidden/non-hidden types.
|
211 |
+
if(NOT DEFINED CMAKE_CXX_VISIBILITY_PRESET)
|
212 |
+
set_target_properties(${target_name} PROPERTIES CXX_VISIBILITY_PRESET "hidden")
|
213 |
+
endif()
|
214 |
+
|
215 |
+
if(NOT DEFINED CMAKE_CUDA_VISIBILITY_PRESET)
|
216 |
+
set_target_properties(${target_name} PROPERTIES CUDA_VISIBILITY_PRESET "hidden")
|
217 |
+
endif()
|
218 |
+
|
219 |
+
# If we don't pass a WITH_SOABI or WITHOUT_SOABI, use our own default handling of extensions
|
220 |
+
if(NOT ARG_WITHOUT_SOABI AND NOT "WITH_SOABI" IN_LIST ARG_UNPARSED_ARGUMENTS)
|
221 |
+
pybind11_extension(${target_name})
|
222 |
+
endif()
|
223 |
+
|
224 |
+
if(ARG_NO_EXTRAS)
|
225 |
+
return()
|
226 |
+
endif()
|
227 |
+
|
228 |
+
if(NOT DEFINED CMAKE_INTERPROCEDURAL_OPTIMIZATION)
|
229 |
+
if(ARG_THIN_LTO)
|
230 |
+
target_link_libraries(${target_name} PRIVATE pybind11::thin_lto)
|
231 |
+
else()
|
232 |
+
target_link_libraries(${target_name} PRIVATE pybind11::lto)
|
233 |
+
endif()
|
234 |
+
endif()
|
235 |
+
|
236 |
+
if(NOT MSVC AND NOT ${CMAKE_BUILD_TYPE} MATCHES Debug|RelWithDebInfo)
|
237 |
+
# Strip unnecessary sections of the binary on Linux/macOS
|
238 |
+
pybind11_strip(${target_name})
|
239 |
+
endif()
|
240 |
+
|
241 |
+
if(MSVC)
|
242 |
+
target_link_libraries(${target_name} PRIVATE pybind11::windows_extras)
|
243 |
+
endif()
|
244 |
+
|
245 |
+
if(ARG_OPT_SIZE)
|
246 |
+
target_link_libraries(${target_name} PRIVATE pybind11::opt_size)
|
247 |
+
endif()
|
248 |
+
endfunction()
|
249 |
+
|
250 |
+
function(pybind11_extension name)
|
251 |
+
# The extension is precomputed
|
252 |
+
set_target_properties(${name} PROPERTIES PREFIX "" SUFFIX "${PYTHON_MODULE_EXTENSION}")
|
253 |
+
|
254 |
+
endfunction()
|
third-party/DPVO/DPViewer/pybind11/tools/pybind11Tools.cmake
ADDED
@@ -0,0 +1,227 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# tools/pybind11Tools.cmake -- Build system for the pybind11 modules
|
2 |
+
#
|
3 |
+
# Copyright (c) 2020 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 |
+
# include_guard(global) (pre-CMake 3.10)
|
9 |
+
if(TARGET pybind11::python_headers)
|
10 |
+
return()
|
11 |
+
endif()
|
12 |
+
|
13 |
+
# Built-in in CMake 3.5+
|
14 |
+
include(CMakeParseArguments)
|
15 |
+
|
16 |
+
if(pybind11_FIND_QUIETLY)
|
17 |
+
set(_pybind11_quiet QUIET)
|
18 |
+
else()
|
19 |
+
set(_pybind11_quiet "")
|
20 |
+
endif()
|
21 |
+
|
22 |
+
# If this is the first run, PYTHON_VERSION can stand in for PYBIND11_PYTHON_VERSION
|
23 |
+
if(NOT DEFINED PYBIND11_PYTHON_VERSION AND DEFINED PYTHON_VERSION)
|
24 |
+
message(WARNING "Set PYBIND11_PYTHON_VERSION to search for a specific version, not "
|
25 |
+
"PYTHON_VERSION (which is an output). Assuming that is what you "
|
26 |
+
"meant to do and continuing anyway.")
|
27 |
+
set(PYBIND11_PYTHON_VERSION
|
28 |
+
"${PYTHON_VERSION}"
|
29 |
+
CACHE STRING "Python version to use for compiling modules")
|
30 |
+
unset(PYTHON_VERSION)
|
31 |
+
unset(PYTHON_VERSION CACHE)
|
32 |
+
elseif(DEFINED PYBIND11_PYTHON_VERSION)
|
33 |
+
# If this is set as a normal variable, promote it
|
34 |
+
set(PYBIND11_PYTHON_VERSION
|
35 |
+
"${PYBIND11_PYTHON_VERSION}"
|
36 |
+
CACHE STRING "Python version to use for compiling modules")
|
37 |
+
else()
|
38 |
+
# Make an empty cache variable.
|
39 |
+
set(PYBIND11_PYTHON_VERSION
|
40 |
+
""
|
41 |
+
CACHE STRING "Python version to use for compiling modules")
|
42 |
+
endif()
|
43 |
+
|
44 |
+
# A user can set versions manually too
|
45 |
+
set(Python_ADDITIONAL_VERSIONS
|
46 |
+
"3.11;3.10;3.9;3.8;3.7;3.6"
|
47 |
+
CACHE INTERNAL "")
|
48 |
+
|
49 |
+
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}")
|
50 |
+
find_package(PythonLibsNew ${PYBIND11_PYTHON_VERSION} MODULE REQUIRED ${_pybind11_quiet})
|
51 |
+
list(REMOVE_AT CMAKE_MODULE_PATH -1)
|
52 |
+
|
53 |
+
# Makes a normal variable a cached variable
|
54 |
+
macro(_PYBIND11_PROMOTE_TO_CACHE NAME)
|
55 |
+
set(_tmp_ptc "${${NAME}}")
|
56 |
+
# CMake 3.21 complains if a cached variable is shadowed by a normal one
|
57 |
+
unset(${NAME})
|
58 |
+
set(${NAME}
|
59 |
+
"${_tmp_ptc}"
|
60 |
+
CACHE INTERNAL "")
|
61 |
+
endmacro()
|
62 |
+
|
63 |
+
# Cache variables so pybind11_add_module can be used in parent projects
|
64 |
+
_pybind11_promote_to_cache(PYTHON_INCLUDE_DIRS)
|
65 |
+
_pybind11_promote_to_cache(PYTHON_LIBRARIES)
|
66 |
+
_pybind11_promote_to_cache(PYTHON_MODULE_PREFIX)
|
67 |
+
_pybind11_promote_to_cache(PYTHON_MODULE_EXTENSION)
|
68 |
+
_pybind11_promote_to_cache(PYTHON_VERSION_MAJOR)
|
69 |
+
_pybind11_promote_to_cache(PYTHON_VERSION_MINOR)
|
70 |
+
_pybind11_promote_to_cache(PYTHON_VERSION)
|
71 |
+
_pybind11_promote_to_cache(PYTHON_IS_DEBUG)
|
72 |
+
|
73 |
+
if(PYBIND11_MASTER_PROJECT)
|
74 |
+
if(PYTHON_MODULE_EXTENSION MATCHES "pypy")
|
75 |
+
if(NOT DEFINED PYPY_VERSION)
|
76 |
+
execute_process(
|
77 |
+
COMMAND ${PYTHON_EXECUTABLE} -c
|
78 |
+
[=[import sys; sys.stdout.write(".".join(map(str, sys.pypy_version_info[:3])))]=]
|
79 |
+
OUTPUT_VARIABLE pypy_version)
|
80 |
+
set(PYPY_VERSION
|
81 |
+
${pypy_version}
|
82 |
+
CACHE INTERNAL "")
|
83 |
+
endif()
|
84 |
+
message(STATUS "PYPY ${PYPY_VERSION} (Py ${PYTHON_VERSION})")
|
85 |
+
else()
|
86 |
+
message(STATUS "PYTHON ${PYTHON_VERSION}")
|
87 |
+
endif()
|
88 |
+
endif()
|
89 |
+
|
90 |
+
# Only add Python for build - must be added during the import for config since
|
91 |
+
# it has to be re-discovered.
|
92 |
+
#
|
93 |
+
# This needs to be an target to it is included after the local pybind11
|
94 |
+
# directory, just in case there are multiple versions of pybind11, we want the
|
95 |
+
# one we expect.
|
96 |
+
add_library(pybind11::python_headers INTERFACE IMPORTED)
|
97 |
+
set_property(TARGET pybind11::python_headers PROPERTY INTERFACE_INCLUDE_DIRECTORIES
|
98 |
+
"$<BUILD_INTERFACE:${PYTHON_INCLUDE_DIRS}>")
|
99 |
+
set_property(
|
100 |
+
TARGET pybind11::pybind11
|
101 |
+
APPEND
|
102 |
+
PROPERTY INTERFACE_LINK_LIBRARIES pybind11::python_headers)
|
103 |
+
|
104 |
+
set(pybind11_INCLUDE_DIRS
|
105 |
+
"${pybind11_INCLUDE_DIR}" "${PYTHON_INCLUDE_DIRS}"
|
106 |
+
CACHE INTERNAL "Directories where pybind11 and possibly Python headers are located")
|
107 |
+
|
108 |
+
# Python debug libraries expose slightly different objects before 3.8
|
109 |
+
# https://docs.python.org/3.6/c-api/intro.html#debugging-builds
|
110 |
+
# https://stackoverflow.com/questions/39161202/how-to-work-around-missing-pymodule-create2-in-amd64-win-python35-d-lib
|
111 |
+
if(PYTHON_IS_DEBUG)
|
112 |
+
set_property(
|
113 |
+
TARGET pybind11::pybind11
|
114 |
+
APPEND
|
115 |
+
PROPERTY INTERFACE_COMPILE_DEFINITIONS Py_DEBUG)
|
116 |
+
endif()
|
117 |
+
|
118 |
+
if(CMAKE_VERSION VERSION_LESS 3.11)
|
119 |
+
set_property(
|
120 |
+
TARGET pybind11::module
|
121 |
+
APPEND
|
122 |
+
PROPERTY
|
123 |
+
INTERFACE_LINK_LIBRARIES
|
124 |
+
pybind11::python_link_helper
|
125 |
+
"$<$<OR:$<PLATFORM_ID:Windows>,$<PLATFORM_ID:Cygwin>>:$<BUILD_INTERFACE:${PYTHON_LIBRARIES}>>"
|
126 |
+
)
|
127 |
+
|
128 |
+
set_property(
|
129 |
+
TARGET pybind11::embed
|
130 |
+
APPEND
|
131 |
+
PROPERTY INTERFACE_LINK_LIBRARIES pybind11::pybind11 $<BUILD_INTERFACE:${PYTHON_LIBRARIES}>)
|
132 |
+
else()
|
133 |
+
target_link_libraries(
|
134 |
+
pybind11::module
|
135 |
+
INTERFACE
|
136 |
+
pybind11::python_link_helper
|
137 |
+
"$<$<OR:$<PLATFORM_ID:Windows>,$<PLATFORM_ID:Cygwin>>:$<BUILD_INTERFACE:${PYTHON_LIBRARIES}>>"
|
138 |
+
)
|
139 |
+
|
140 |
+
target_link_libraries(pybind11::embed INTERFACE pybind11::pybind11
|
141 |
+
$<BUILD_INTERFACE:${PYTHON_LIBRARIES}>)
|
142 |
+
|
143 |
+
endif()
|
144 |
+
|
145 |
+
function(pybind11_extension name)
|
146 |
+
# The prefix and extension are provided by FindPythonLibsNew.cmake
|
147 |
+
set_target_properties(${name} PROPERTIES PREFIX "${PYTHON_MODULE_PREFIX}"
|
148 |
+
SUFFIX "${PYTHON_MODULE_EXTENSION}")
|
149 |
+
endfunction()
|
150 |
+
|
151 |
+
# Build a Python extension module:
|
152 |
+
# pybind11_add_module(<name> [MODULE | SHARED] [EXCLUDE_FROM_ALL]
|
153 |
+
# [NO_EXTRAS] [THIN_LTO] [OPT_SIZE] source1 [source2 ...])
|
154 |
+
#
|
155 |
+
function(pybind11_add_module target_name)
|
156 |
+
set(options "MODULE;SHARED;EXCLUDE_FROM_ALL;NO_EXTRAS;SYSTEM;THIN_LTO;OPT_SIZE")
|
157 |
+
cmake_parse_arguments(ARG "${options}" "" "" ${ARGN})
|
158 |
+
|
159 |
+
if(ARG_MODULE AND ARG_SHARED)
|
160 |
+
message(FATAL_ERROR "Can't be both MODULE and SHARED")
|
161 |
+
elseif(ARG_SHARED)
|
162 |
+
set(lib_type SHARED)
|
163 |
+
else()
|
164 |
+
set(lib_type MODULE)
|
165 |
+
endif()
|
166 |
+
|
167 |
+
if(ARG_EXCLUDE_FROM_ALL)
|
168 |
+
set(exclude_from_all EXCLUDE_FROM_ALL)
|
169 |
+
else()
|
170 |
+
set(exclude_from_all "")
|
171 |
+
endif()
|
172 |
+
|
173 |
+
add_library(${target_name} ${lib_type} ${exclude_from_all} ${ARG_UNPARSED_ARGUMENTS})
|
174 |
+
|
175 |
+
target_link_libraries(${target_name} PRIVATE pybind11::module)
|
176 |
+
|
177 |
+
if(ARG_SYSTEM)
|
178 |
+
message(
|
179 |
+
STATUS
|
180 |
+
"Warning: this does not have an effect - use NO_SYSTEM_FROM_IMPORTED if using imported targets"
|
181 |
+
)
|
182 |
+
endif()
|
183 |
+
|
184 |
+
pybind11_extension(${target_name})
|
185 |
+
|
186 |
+
# -fvisibility=hidden is required to allow multiple modules compiled against
|
187 |
+
# different pybind versions to work properly, and for some features (e.g.
|
188 |
+
# py::module_local). We force it on everything inside the `pybind11`
|
189 |
+
# namespace; also turning it on for a pybind module compilation here avoids
|
190 |
+
# potential warnings or issues from having mixed hidden/non-hidden types.
|
191 |
+
if(NOT DEFINED CMAKE_CXX_VISIBILITY_PRESET)
|
192 |
+
set_target_properties(${target_name} PROPERTIES CXX_VISIBILITY_PRESET "hidden")
|
193 |
+
endif()
|
194 |
+
|
195 |
+
if(NOT DEFINED CMAKE_CUDA_VISIBILITY_PRESET)
|
196 |
+
set_target_properties(${target_name} PROPERTIES CUDA_VISIBILITY_PRESET "hidden")
|
197 |
+
endif()
|
198 |
+
|
199 |
+
if(ARG_NO_EXTRAS)
|
200 |
+
return()
|
201 |
+
endif()
|
202 |
+
|
203 |
+
if(NOT DEFINED CMAKE_INTERPROCEDURAL_OPTIMIZATION)
|
204 |
+
if(ARG_THIN_LTO)
|
205 |
+
target_link_libraries(${target_name} PRIVATE pybind11::thin_lto)
|
206 |
+
else()
|
207 |
+
target_link_libraries(${target_name} PRIVATE pybind11::lto)
|
208 |
+
endif()
|
209 |
+
endif()
|
210 |
+
|
211 |
+
if(NOT MSVC AND NOT ${CMAKE_BUILD_TYPE} MATCHES Debug|RelWithDebInfo)
|
212 |
+
pybind11_strip(${target_name})
|
213 |
+
endif()
|
214 |
+
|
215 |
+
if(MSVC)
|
216 |
+
target_link_libraries(${target_name} PRIVATE pybind11::windows_extras)
|
217 |
+
endif()
|
218 |
+
|
219 |
+
if(ARG_OPT_SIZE)
|
220 |
+
target_link_libraries(${target_name} PRIVATE pybind11::opt_size)
|
221 |
+
endif()
|
222 |
+
endfunction()
|
223 |
+
|
224 |
+
# Provide general way to call common Python commands in "common" file.
|
225 |
+
set(_Python
|
226 |
+
PYTHON
|
227 |
+
CACHE INTERNAL "" FORCE)
|
third-party/DPVO/DPViewer/pybind11/tools/pyproject.toml
ADDED
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
1 |
+
[build-system]
|
2 |
+
requires = ["setuptools>=42", "wheel"]
|
3 |
+
build-backend = "setuptools.build_meta"
|
third-party/DPVO/DPViewer/pybind11/tools/setup_global.py.in
ADDED
@@ -0,0 +1,59 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
#!/usr/bin/env python3
|
2 |
+
|
3 |
+
# Setup script for pybind11-global (in the sdist or in tools/setup_global.py in the repository)
|
4 |
+
# This package is targeted for easy use from CMake.
|
5 |
+
|
6 |
+
import glob
|
7 |
+
import os
|
8 |
+
import re
|
9 |
+
|
10 |
+
# Setuptools has to be before distutils
|
11 |
+
from setuptools import setup
|
12 |
+
|
13 |
+
from distutils.command.install_headers import install_headers
|
14 |
+
|
15 |
+
class InstallHeadersNested(install_headers):
|
16 |
+
def run(self):
|
17 |
+
headers = self.distribution.headers or []
|
18 |
+
for header in headers:
|
19 |
+
# Remove pybind11/include/
|
20 |
+
short_header = header.split("/", 2)[-1]
|
21 |
+
|
22 |
+
dst = os.path.join(self.install_dir, os.path.dirname(short_header))
|
23 |
+
self.mkpath(dst)
|
24 |
+
(out, _) = self.copy_file(header, dst)
|
25 |
+
self.outfiles.append(out)
|
26 |
+
|
27 |
+
|
28 |
+
main_headers = glob.glob("pybind11/include/pybind11/*.h")
|
29 |
+
detail_headers = glob.glob("pybind11/include/pybind11/detail/*.h")
|
30 |
+
stl_headers = glob.glob("pybind11/include/pybind11/stl/*.h")
|
31 |
+
cmake_files = glob.glob("pybind11/share/cmake/pybind11/*.cmake")
|
32 |
+
headers = main_headers + detail_headers + stl_headers
|
33 |
+
|
34 |
+
cmdclass = {"install_headers": InstallHeadersNested}
|
35 |
+
$extra_cmd
|
36 |
+
|
37 |
+
# This will _not_ affect installing from wheels,
|
38 |
+
# only building wheels or installing from SDist.
|
39 |
+
# Primarily intended on Windows, where this is sometimes
|
40 |
+
# customized (for example, conda-forge uses Library/)
|
41 |
+
base = os.environ.get("PYBIND11_GLOBAL_PREFIX", "")
|
42 |
+
|
43 |
+
# Must have a separator
|
44 |
+
if base and not base.endswith("/"):
|
45 |
+
base += "/"
|
46 |
+
|
47 |
+
setup(
|
48 |
+
name="pybind11_global",
|
49 |
+
version="$version",
|
50 |
+
packages=[],
|
51 |
+
headers=headers,
|
52 |
+
data_files=[
|
53 |
+
(base + "share/cmake/pybind11", cmake_files),
|
54 |
+
(base + "include/pybind11", main_headers),
|
55 |
+
(base + "include/pybind11/detail", detail_headers),
|
56 |
+
(base + "include/pybind11/stl", stl_headers),
|
57 |
+
],
|
58 |
+
cmdclass=cmdclass,
|
59 |
+
)
|
third-party/DPVO/DPViewer/pybind11/tools/setup_main.py.in
ADDED
@@ -0,0 +1,40 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
#!/usr/bin/env python3
|
2 |
+
|
3 |
+
# Setup script (in the sdist or in tools/setup_main.py in the repository)
|
4 |
+
|
5 |
+
from setuptools import setup
|
6 |
+
|
7 |
+
cmdclass = {}
|
8 |
+
$extra_cmd
|
9 |
+
|
10 |
+
setup(
|
11 |
+
name="pybind11",
|
12 |
+
version="$version",
|
13 |
+
download_url='https://github.com/pybind/pybind11/tarball/v$version',
|
14 |
+
packages=[
|
15 |
+
"pybind11",
|
16 |
+
"pybind11.include.pybind11",
|
17 |
+
"pybind11.include.pybind11.detail",
|
18 |
+
"pybind11.include.pybind11.stl",
|
19 |
+
"pybind11.share.cmake.pybind11",
|
20 |
+
],
|
21 |
+
package_data={
|
22 |
+
"pybind11": ["py.typed"],
|
23 |
+
"pybind11.include.pybind11": ["*.h"],
|
24 |
+
"pybind11.include.pybind11.detail": ["*.h"],
|
25 |
+
"pybind11.include.pybind11.stl": ["*.h"],
|
26 |
+
"pybind11.share.cmake.pybind11": ["*.cmake"],
|
27 |
+
},
|
28 |
+
extras_require={
|
29 |
+
"global": ["pybind11_global==$version"]
|
30 |
+
},
|
31 |
+
entry_points={
|
32 |
+
"console_scripts": [
|
33 |
+
"pybind11-config = pybind11.__main__:main",
|
34 |
+
],
|
35 |
+
"pipx.run": [
|
36 |
+
"pybind11 = pybind11.__main__:main",
|
37 |
+
]
|
38 |
+
},
|
39 |
+
cmdclass=cmdclass
|
40 |
+
)
|
third-party/DPVO/DPViewer/setup.py
ADDED
@@ -0,0 +1,132 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# -*- coding: utf-8 -*-
|
2 |
+
import os
|
3 |
+
import re
|
4 |
+
import subprocess
|
5 |
+
import sys
|
6 |
+
import torch
|
7 |
+
|
8 |
+
|
9 |
+
from setuptools import setup, Extension
|
10 |
+
from setuptools.command.build_ext import build_ext
|
11 |
+
|
12 |
+
# Convert distutils Windows platform specifiers to CMake -A arguments
|
13 |
+
PLAT_TO_CMAKE = {
|
14 |
+
"win32": "Win32",
|
15 |
+
"win-amd64": "x64",
|
16 |
+
"win-arm32": "ARM",
|
17 |
+
"win-arm64": "ARM64",
|
18 |
+
}
|
19 |
+
|
20 |
+
|
21 |
+
# A CMakeExtension needs a sourcedir instead of a file list.
|
22 |
+
# The name must be the _single_ output extension from the CMake build.
|
23 |
+
# If you need multiple extensions, see scikit-build.
|
24 |
+
class CMakeExtension(Extension):
|
25 |
+
def __init__(self, name, sourcedir=""):
|
26 |
+
Extension.__init__(self, name, sources=[])
|
27 |
+
self.sourcedir = os.path.abspath(sourcedir)
|
28 |
+
|
29 |
+
|
30 |
+
class CMakeBuild(build_ext):
|
31 |
+
def build_extension(self, ext):
|
32 |
+
extdir = os.path.abspath(os.path.dirname(self.get_ext_fullpath(ext.name)))
|
33 |
+
|
34 |
+
# required for auto-detection & inclusion of auxiliary "native" libs
|
35 |
+
if not extdir.endswith(os.path.sep):
|
36 |
+
extdir += os.path.sep
|
37 |
+
|
38 |
+
debug = int(os.environ.get("DEBUG", 0)) if self.debug is None else self.debug
|
39 |
+
cfg = "Debug" if debug else "Release"
|
40 |
+
|
41 |
+
# CMake lets you override the generator - we need to check this.
|
42 |
+
# Can be set with Conda-Build, for example.
|
43 |
+
cmake_generator = os.environ.get("CMAKE_GENERATOR", "")
|
44 |
+
|
45 |
+
# Set Python_EXECUTABLE instead if you use PYBIND11_FINDPYTHON
|
46 |
+
# EXAMPLE_VERSION_INFO shows you how to pass a value into the C++ code
|
47 |
+
# from Python.
|
48 |
+
|
49 |
+
cmake_args = [
|
50 |
+
"-DCMAKE_LIBRARY_OUTPUT_DIRECTORY={}".format(extdir),
|
51 |
+
"-DPYTHON_EXECUTABLE={}".format(sys.executable),
|
52 |
+
"-DCMAKE_BUILD_TYPE={}".format(cfg), # not used on MSVC, but no harm
|
53 |
+
"-DTORCH_PATH={}".format(torch.__path__[0])
|
54 |
+
]
|
55 |
+
build_args = ["--verbose"]
|
56 |
+
# Adding CMake arguments set as environment variable
|
57 |
+
# (needed e.g. to build for ARM OSx on conda-forge)
|
58 |
+
if "CMAKE_ARGS" in os.environ:
|
59 |
+
cmake_args += [item for item in os.environ["CMAKE_ARGS"].split(" ") if item]
|
60 |
+
|
61 |
+
# In this example, we pass in the version to C++. You might not need to.
|
62 |
+
cmake_args += [
|
63 |
+
"-DEXAMPLE_VERSION_INFO={}".format(self.distribution.get_version())
|
64 |
+
]
|
65 |
+
|
66 |
+
if self.compiler.compiler_type != "msvc":
|
67 |
+
# Using Ninja-build since it a) is available as a wheel and b)
|
68 |
+
# multithreads automatically. MSVC would require all variables be
|
69 |
+
# exported for Ninja to pick it up, which is a little tricky to do.
|
70 |
+
# Users can override the generator with CMAKE_GENERATOR in CMake
|
71 |
+
# 3.15+.
|
72 |
+
if not cmake_generator:
|
73 |
+
try:
|
74 |
+
import ninja # noqa: F401
|
75 |
+
|
76 |
+
cmake_args += ["-GNinja"]
|
77 |
+
except ImportError:
|
78 |
+
pass
|
79 |
+
|
80 |
+
else:
|
81 |
+
|
82 |
+
# Single config generators are handled "normally"
|
83 |
+
single_config = any(x in cmake_generator for x in {"NMake", "Ninja"})
|
84 |
+
|
85 |
+
# CMake allows an arch-in-generator style for backward compatibility
|
86 |
+
contains_arch = any(x in cmake_generator for x in {"ARM", "Win64"})
|
87 |
+
|
88 |
+
# Specify the arch if using MSVC generator, but only if it doesn't
|
89 |
+
# contain a backward-compatibility arch spec already in the
|
90 |
+
# generator name.
|
91 |
+
if not single_config and not contains_arch:
|
92 |
+
cmake_args += ["-A", PLAT_TO_CMAKE[self.plat_name]]
|
93 |
+
|
94 |
+
# Multi-config generators have a different way to specify configs
|
95 |
+
if not single_config:
|
96 |
+
cmake_args += [
|
97 |
+
"-DCMAKE_LIBRARY_OUTPUT_DIRECTORY_{}={}".format(cfg.upper(), extdir)
|
98 |
+
]
|
99 |
+
build_args += ["--config", cfg]
|
100 |
+
|
101 |
+
if sys.platform.startswith("darwin"):
|
102 |
+
# Cross-compile support for macOS - respect ARCHFLAGS if set
|
103 |
+
archs = re.findall(r"-arch (\S+)", os.environ.get("ARCHFLAGS", ""))
|
104 |
+
if archs:
|
105 |
+
cmake_args += ["-DCMAKE_OSX_ARCHITECTURES={}".format(";".join(archs))]
|
106 |
+
|
107 |
+
build_args += ["-j"]
|
108 |
+
|
109 |
+
if not os.path.exists(self.build_temp):
|
110 |
+
os.makedirs(self.build_temp)
|
111 |
+
|
112 |
+
subprocess.check_call(
|
113 |
+
["cmake", ext.sourcedir] + cmake_args, cwd=self.build_temp,
|
114 |
+
)
|
115 |
+
|
116 |
+
subprocess.check_call(
|
117 |
+
["cmake", "--build", "."] + build_args, cwd=self.build_temp
|
118 |
+
)
|
119 |
+
|
120 |
+
|
121 |
+
# The information here can also be placed in setup.cfg - better separation of
|
122 |
+
# logic and declaration, and simpler if you include description/version in a file.
|
123 |
+
setup(
|
124 |
+
name="dpviewer",
|
125 |
+
version="0.0.1",
|
126 |
+
author="Zachary Teed",
|
127 |
+
packages=['dpviewer'],
|
128 |
+
ext_modules=[CMakeExtension("dpviewer")],
|
129 |
+
cmdclass={"build_ext": CMakeBuild},
|
130 |
+
zip_safe=False,
|
131 |
+
extras_require={"test": ["pytest"]},
|
132 |
+
)
|
third-party/DPVO/dpvo/__init__.py
ADDED
File without changes
|
third-party/DPVO/dpvo/altcorr/__init__.py
ADDED
@@ -0,0 +1 @@
|
|
|
|
|
1 |
+
from .correlation import corr, patchify
|
third-party/DPVO/dpvo/altcorr/correlation.cpp
ADDED
@@ -0,0 +1,63 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
#include <torch/extension.h>
|
2 |
+
#include <vector>
|
3 |
+
|
4 |
+
// CUDA forward declarations
|
5 |
+
std::vector<torch::Tensor> corr_cuda_forward(
|
6 |
+
torch::Tensor fmap1,
|
7 |
+
torch::Tensor fmap2,
|
8 |
+
torch::Tensor coords,
|
9 |
+
torch::Tensor ii,
|
10 |
+
torch::Tensor jj,
|
11 |
+
int radius);
|
12 |
+
|
13 |
+
std::vector<torch::Tensor> corr_cuda_backward(
|
14 |
+
torch::Tensor fmap1,
|
15 |
+
torch::Tensor fmap2,
|
16 |
+
torch::Tensor coords,
|
17 |
+
torch::Tensor ii,
|
18 |
+
torch::Tensor jj,
|
19 |
+
torch::Tensor corr_grad,
|
20 |
+
int radius);
|
21 |
+
|
22 |
+
std::vector<torch::Tensor> patchify_cuda_forward(
|
23 |
+
torch::Tensor net, torch::Tensor coords, int radius);
|
24 |
+
|
25 |
+
std::vector<torch::Tensor> patchify_cuda_backward(
|
26 |
+
torch::Tensor net, torch::Tensor coords, torch::Tensor gradient, int radius);
|
27 |
+
|
28 |
+
std::vector<torch::Tensor> corr_forward(
|
29 |
+
torch::Tensor fmap1,
|
30 |
+
torch::Tensor fmap2,
|
31 |
+
torch::Tensor coords,
|
32 |
+
torch::Tensor ii,
|
33 |
+
torch::Tensor jj, int radius) {
|
34 |
+
return corr_cuda_forward(fmap1, fmap2, coords, ii, jj, radius);
|
35 |
+
}
|
36 |
+
|
37 |
+
std::vector<torch::Tensor> corr_backward(
|
38 |
+
torch::Tensor fmap1,
|
39 |
+
torch::Tensor fmap2,
|
40 |
+
torch::Tensor coords,
|
41 |
+
torch::Tensor ii,
|
42 |
+
torch::Tensor jj,
|
43 |
+
torch::Tensor corr_grad, int radius) {
|
44 |
+
return corr_cuda_backward(fmap1, fmap2, coords, ii, jj, corr_grad, radius);
|
45 |
+
}
|
46 |
+
|
47 |
+
std::vector<torch::Tensor> patchify_forward(
|
48 |
+
torch::Tensor net, torch::Tensor coords, int radius) {
|
49 |
+
return patchify_cuda_forward(net, coords, radius);
|
50 |
+
}
|
51 |
+
|
52 |
+
std::vector<torch::Tensor> patchify_backward(
|
53 |
+
torch::Tensor net, torch::Tensor coords, torch::Tensor gradient, int radius) {
|
54 |
+
return patchify_cuda_backward(net, coords, gradient, radius);
|
55 |
+
}
|
56 |
+
|
57 |
+
PYBIND11_MODULE(TORCH_EXTENSION_NAME, m) {
|
58 |
+
m.def("forward", &corr_forward, "CORR forward");
|
59 |
+
m.def("backward", &corr_backward, "CORR backward");
|
60 |
+
|
61 |
+
m.def("patchify_forward", &patchify_forward, "PATCHIFY forward");
|
62 |
+
m.def("patchify_backward", &patchify_backward, "PATCHIFY backward");
|
63 |
+
}
|
third-party/DPVO/dpvo/altcorr/correlation.py
ADDED
@@ -0,0 +1,74 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import torch
|
2 |
+
import cuda_corr
|
3 |
+
|
4 |
+
class CorrLayer(torch.autograd.Function):
|
5 |
+
@staticmethod
|
6 |
+
def forward(ctx, fmap1, fmap2, coords, ii, jj, radius, dropout):
|
7 |
+
""" forward correlation """
|
8 |
+
ctx.save_for_backward(fmap1, fmap2, coords, ii, jj)
|
9 |
+
ctx.radius = radius
|
10 |
+
ctx.dropout = dropout
|
11 |
+
corr, = cuda_corr.forward(fmap1, fmap2, coords, ii, jj, radius)
|
12 |
+
|
13 |
+
return corr
|
14 |
+
|
15 |
+
@staticmethod
|
16 |
+
def backward(ctx, grad):
|
17 |
+
""" backward correlation """
|
18 |
+
fmap1, fmap2, coords, ii, jj = ctx.saved_tensors
|
19 |
+
|
20 |
+
if ctx.dropout < 1:
|
21 |
+
perm = torch.rand(len(ii), device="cuda") < ctx.dropout
|
22 |
+
coords = coords[:,perm]
|
23 |
+
grad = grad[:,perm]
|
24 |
+
ii = ii[perm]
|
25 |
+
jj = jj[perm]
|
26 |
+
|
27 |
+
fmap1_grad, fmap2_grad = \
|
28 |
+
cuda_corr.backward(fmap1, fmap2, coords, ii, jj, grad, ctx.radius)
|
29 |
+
|
30 |
+
return fmap1_grad, fmap2_grad, None, None, None, None, None
|
31 |
+
|
32 |
+
|
33 |
+
class PatchLayer(torch.autograd.Function):
|
34 |
+
@staticmethod
|
35 |
+
def forward(ctx, net, coords, radius):
|
36 |
+
""" forward patchify """
|
37 |
+
ctx.radius = radius
|
38 |
+
ctx.save_for_backward(net, coords)
|
39 |
+
|
40 |
+
patches, = cuda_corr.patchify_forward(net, coords, radius)
|
41 |
+
return patches
|
42 |
+
|
43 |
+
@staticmethod
|
44 |
+
def backward(ctx, grad):
|
45 |
+
""" backward patchify """
|
46 |
+
net, coords = ctx.saved_tensors
|
47 |
+
grad, = cuda_corr.patchify_backward(net, coords, grad, ctx.radius)
|
48 |
+
|
49 |
+
return grad, None, None
|
50 |
+
|
51 |
+
def patchify(net, coords, radius, mode='bilinear'):
|
52 |
+
""" extract patches """
|
53 |
+
|
54 |
+
patches = PatchLayer.apply(net, coords, radius)
|
55 |
+
|
56 |
+
if mode == 'bilinear':
|
57 |
+
offset = (coords - coords.floor()).to(net.device)
|
58 |
+
dx, dy = offset[:,:,None,None,None].unbind(dim=-1)
|
59 |
+
|
60 |
+
d = 2 * radius + 1
|
61 |
+
x00 = (1-dy) * (1-dx) * patches[...,:d,:d]
|
62 |
+
x01 = (1-dy) * ( dx) * patches[...,:d,1:]
|
63 |
+
x10 = ( dy) * (1-dx) * patches[...,1:,:d]
|
64 |
+
x11 = ( dy) * ( dx) * patches[...,1:,1:]
|
65 |
+
|
66 |
+
return x00 + x01 + x10 + x11
|
67 |
+
|
68 |
+
return patches
|
69 |
+
|
70 |
+
|
71 |
+
def corr(fmap1, fmap2, coords, ii, jj, radius=1, dropout=1):
|
72 |
+
return CorrLayer.apply(fmap1, fmap2, coords, ii, jj, radius, dropout)
|
73 |
+
|
74 |
+
|
third-party/DPVO/dpvo/altcorr/correlation_kernel.cu
ADDED
@@ -0,0 +1,333 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
#include <torch/extension.h>
|
2 |
+
#include <THC/THCAtomics.cuh>
|
3 |
+
#include <vector>
|
4 |
+
#include <iostream>
|
5 |
+
|
6 |
+
using namespace torch::indexing;
|
7 |
+
|
8 |
+
#define THREADS 256
|
9 |
+
#define BLOCKS(n) (n + THREADS - 1) / THREADS
|
10 |
+
|
11 |
+
__forceinline__ __device__
|
12 |
+
bool within_bounds(int h, int w, int H, int W) {
|
13 |
+
return h >= 0 && h < H && w >= 0 && w < W;
|
14 |
+
}
|
15 |
+
|
16 |
+
template <typename scalar_t>
|
17 |
+
__global__ void patchify_forward_kernel(int R,
|
18 |
+
const torch::PackedTensorAccessor32<scalar_t,4,torch::RestrictPtrTraits> net,
|
19 |
+
const torch::PackedTensorAccessor32<float,3,torch::RestrictPtrTraits> coords,
|
20 |
+
torch::PackedTensorAccessor32<scalar_t,5,torch::RestrictPtrTraits> patches)
|
21 |
+
{
|
22 |
+
// diameter
|
23 |
+
const int D = 2*R + 2;
|
24 |
+
|
25 |
+
const int B = coords.size(0);
|
26 |
+
const int M = coords.size(1);
|
27 |
+
const int C = net.size(1);
|
28 |
+
const int H = net.size(2);
|
29 |
+
const int W = net.size(3);
|
30 |
+
|
31 |
+
int n = blockIdx.x * blockDim.x + threadIdx.x;
|
32 |
+
if (n < B * M * D * D) {
|
33 |
+
const int ii = n % D; n /= D;
|
34 |
+
const int jj = n % D; n /= D;
|
35 |
+
const int m = n % M; n /= M;
|
36 |
+
|
37 |
+
const float x = coords[n][m][0];
|
38 |
+
const float y = coords[n][m][1];
|
39 |
+
const int i = static_cast<int>(floor(y)) + (ii - R);
|
40 |
+
const int j = static_cast<int>(floor(x)) + (jj - R);
|
41 |
+
|
42 |
+
if (within_bounds(i, j, H, W)) {
|
43 |
+
for (int k=0; k<C; k++)
|
44 |
+
patches[n][m][k][ii][jj] = net[n][k][i][j];
|
45 |
+
}
|
46 |
+
}
|
47 |
+
}
|
48 |
+
|
49 |
+
template <typename scalar_t>
|
50 |
+
__global__ void patchify_backward_kernel(int R,
|
51 |
+
const torch::PackedTensorAccessor32<scalar_t,5,torch::RestrictPtrTraits> patch_gradient,
|
52 |
+
const torch::PackedTensorAccessor32<float,3,torch::RestrictPtrTraits> coords,
|
53 |
+
torch::PackedTensorAccessor32<scalar_t,4,torch::RestrictPtrTraits> gradient)
|
54 |
+
{
|
55 |
+
// diameter
|
56 |
+
const int D = 2*R + 2;
|
57 |
+
|
58 |
+
const int B = coords.size(0);
|
59 |
+
const int M = coords.size(1);
|
60 |
+
const int C = gradient.size(1);
|
61 |
+
const int H = gradient.size(2);
|
62 |
+
const int W = gradient.size(3);
|
63 |
+
|
64 |
+
int n = blockIdx.x * blockDim.x + threadIdx.x;
|
65 |
+
if (n < B * M * D * D) {
|
66 |
+
const int ii = n % D; n /= D;
|
67 |
+
const int jj = n % D; n /= D;
|
68 |
+
const int m = n % M; n /= M;
|
69 |
+
|
70 |
+
const float x = coords[n][m][0];
|
71 |
+
const float y = coords[n][m][1];
|
72 |
+
const int i = static_cast<int>(floor(y)) + (ii - R);
|
73 |
+
const int j = static_cast<int>(floor(x)) + (jj - R);
|
74 |
+
|
75 |
+
if (within_bounds(i, j, H, W)) {
|
76 |
+
for (int k=0; k<C; k++)
|
77 |
+
atomicAdd(&gradient[n][k][i][j], patch_gradient[n][m][k][ii][jj]);
|
78 |
+
}
|
79 |
+
}
|
80 |
+
}
|
81 |
+
|
82 |
+
template <typename scalar_t>
|
83 |
+
__global__ void corr_forward_kernel(int R,
|
84 |
+
const torch::PackedTensorAccessor32<scalar_t,5,torch::RestrictPtrTraits> fmap1,
|
85 |
+
const torch::PackedTensorAccessor32<scalar_t,5,torch::RestrictPtrTraits> fmap2,
|
86 |
+
const torch::PackedTensorAccessor32<float,5,torch::RestrictPtrTraits> coords,
|
87 |
+
const torch::PackedTensorAccessor32<long,1,torch::RestrictPtrTraits> us,
|
88 |
+
const torch::PackedTensorAccessor32<long,1,torch::RestrictPtrTraits> vs,
|
89 |
+
torch::PackedTensorAccessor32<scalar_t,6,torch::RestrictPtrTraits> corr)
|
90 |
+
{
|
91 |
+
// diameter
|
92 |
+
const int D = 2*R + 2;
|
93 |
+
|
94 |
+
const int B = coords.size(0);
|
95 |
+
const int M = coords.size(1);
|
96 |
+
const int H = coords.size(3);
|
97 |
+
const int W = coords.size(4);
|
98 |
+
|
99 |
+
const int C = fmap1.size(2);
|
100 |
+
const int H2 = fmap2.size(3);
|
101 |
+
const int W2 = fmap2.size(4);
|
102 |
+
|
103 |
+
int n = blockIdx.x * blockDim.x + threadIdx.x;
|
104 |
+
|
105 |
+
if (n < B * M * H * W * D * D) {
|
106 |
+
const int jj = n % D; n /= D;
|
107 |
+
const int ii = n % D; n /= D;
|
108 |
+
const int j0 = n % W; n /= W;
|
109 |
+
const int i0 = n % H; n /= H;
|
110 |
+
const int m = n % M; n /= M;
|
111 |
+
|
112 |
+
const int ix = us[m];
|
113 |
+
const int jx = vs[m];
|
114 |
+
|
115 |
+
const float x = coords[n][m][0][i0][j0];
|
116 |
+
const float y = coords[n][m][1][i0][j0];
|
117 |
+
|
118 |
+
const int i1 = static_cast<int>(floor(y)) + (ii - R);
|
119 |
+
const int j1 = static_cast<int>(floor(x)) + (jj - R);
|
120 |
+
|
121 |
+
scalar_t s = 0;
|
122 |
+
if (within_bounds(i1, j1, H2, W2)) {
|
123 |
+
|
124 |
+
#pragma unroll 8
|
125 |
+
for (int i=0; i<C; i+=8) {
|
126 |
+
scalar_t f1[8]; for (int j=0; j<8; j++) f1[j] = fmap1[n][ix][i+j][i0][j0];
|
127 |
+
scalar_t f2[8]; for (int j=0; j<8; j++) f2[j] = fmap2[n][jx][i+j][i1][j1];
|
128 |
+
|
129 |
+
#pragma unroll
|
130 |
+
for (int j=0; j<8; j++) s += f1[j] * f2[j];
|
131 |
+
}
|
132 |
+
}
|
133 |
+
|
134 |
+
corr[n][m][ii][jj][i0][j0] = s;
|
135 |
+
}
|
136 |
+
}
|
137 |
+
|
138 |
+
|
139 |
+
template <typename scalar_t>
|
140 |
+
__global__ void corr_backward_kernel(int R,
|
141 |
+
const torch::PackedTensorAccessor32<scalar_t,5,torch::RestrictPtrTraits> fmap1,
|
142 |
+
const torch::PackedTensorAccessor32<scalar_t,5,torch::RestrictPtrTraits> fmap2,
|
143 |
+
const torch::PackedTensorAccessor32<float,5,torch::RestrictPtrTraits> coords,
|
144 |
+
const torch::PackedTensorAccessor32<long,1,torch::RestrictPtrTraits> us,
|
145 |
+
const torch::PackedTensorAccessor32<long,1,torch::RestrictPtrTraits> vs,
|
146 |
+
const torch::PackedTensorAccessor32<float,6,torch::RestrictPtrTraits> corr_grad,
|
147 |
+
torch::PackedTensorAccessor32<scalar_t,5,torch::RestrictPtrTraits> fmap1_grad,
|
148 |
+
torch::PackedTensorAccessor32<scalar_t,5,torch::RestrictPtrTraits> fmap2_grad)
|
149 |
+
{
|
150 |
+
// diameter
|
151 |
+
const int D = 2*R + 2;
|
152 |
+
|
153 |
+
const int B = coords.size(0);
|
154 |
+
const int M = coords.size(1);
|
155 |
+
const int H = coords.size(3);
|
156 |
+
const int W = coords.size(4);
|
157 |
+
|
158 |
+
const int C = fmap1.size(2);
|
159 |
+
const int H2 = fmap2.size(3);
|
160 |
+
const int W2 = fmap2.size(4);
|
161 |
+
|
162 |
+
int n = blockIdx.x * blockDim.x + threadIdx.x;
|
163 |
+
|
164 |
+
if (n < B * M * H * W * D * D) {
|
165 |
+
const int jj = n % D; n /= D;
|
166 |
+
const int ii = n % D; n /= D;
|
167 |
+
const int j0 = n % W; n /= W;
|
168 |
+
const int i0 = n % H; n /= H;
|
169 |
+
const int m = n % M; n /= M;
|
170 |
+
|
171 |
+
const int ix = us[m];
|
172 |
+
const int jx = vs[m];
|
173 |
+
|
174 |
+
const float x = coords[n][m][0][i0][j0];
|
175 |
+
const float y = coords[n][m][1][i0][j0];
|
176 |
+
|
177 |
+
const int i1 = static_cast<int>(floor(y)) + (ii - R);
|
178 |
+
const int j1 = static_cast<int>(floor(x)) + (jj - R);
|
179 |
+
|
180 |
+
const scalar_t g = (scalar_t) corr_grad[n][m][ii][jj][i0][j0];
|
181 |
+
|
182 |
+
if (within_bounds(i1, j1, H2, W2)) {
|
183 |
+
#pragma unroll 32
|
184 |
+
for (int i=0; i<C; i++) {
|
185 |
+
atomicAdd(&fmap1_grad[n][ix][i][i0][j0], g * fmap2[n][jx][i][i1][j1]);
|
186 |
+
atomicAdd(&fmap2_grad[n][jx][i][i1][j1], g * fmap1[n][ix][i][i0][j0]);
|
187 |
+
}
|
188 |
+
}
|
189 |
+
}
|
190 |
+
}
|
191 |
+
|
192 |
+
|
193 |
+
std::vector<torch::Tensor> corr_cuda_forward(
|
194 |
+
torch::Tensor fmap1,
|
195 |
+
torch::Tensor fmap2,
|
196 |
+
torch::Tensor coords,
|
197 |
+
torch::Tensor ii,
|
198 |
+
torch::Tensor jj,
|
199 |
+
int radius)
|
200 |
+
{
|
201 |
+
const int B = coords.size(0);
|
202 |
+
const int M = coords.size(1);
|
203 |
+
|
204 |
+
const int H = coords.size(3);
|
205 |
+
const int W = coords.size(4);
|
206 |
+
const int D = 2 * radius + 2;
|
207 |
+
|
208 |
+
auto opts = fmap1.options();
|
209 |
+
auto corr = torch::empty({B, M, D, D, H, W}, opts);
|
210 |
+
|
211 |
+
AT_DISPATCH_FLOATING_TYPES_AND_HALF(fmap1.type(), "corr_forward_kernel", ([&] {
|
212 |
+
corr_forward_kernel<scalar_t><<<BLOCKS(B * M * H * W * D * D), THREADS>>>(radius,
|
213 |
+
fmap1.packed_accessor32<scalar_t,5,torch::RestrictPtrTraits>(),
|
214 |
+
fmap2.packed_accessor32<scalar_t,5,torch::RestrictPtrTraits>(),
|
215 |
+
coords.packed_accessor32<float,5,torch::RestrictPtrTraits>(),
|
216 |
+
ii.packed_accessor32<long,1,torch::RestrictPtrTraits>(),
|
217 |
+
jj.packed_accessor32<long,1,torch::RestrictPtrTraits>(),
|
218 |
+
corr.packed_accessor32<scalar_t,6,torch::RestrictPtrTraits>());
|
219 |
+
}));
|
220 |
+
|
221 |
+
torch::Tensor x = coords.index({Slice(), Slice(), 0, None, None});
|
222 |
+
torch::Tensor y = coords.index({Slice(), Slice(), 1, None, None});
|
223 |
+
torch::Tensor dx = x - x.floor(); dx = dx.to(fmap1.dtype());
|
224 |
+
torch::Tensor dy = y - y.floor(); dy = dy.to(fmap2.dtype());
|
225 |
+
|
226 |
+
torch::Tensor out;
|
227 |
+
out = (1 - dx) * (1 - dy) * corr.index({Slice(), Slice(), Slice(0, D-1), Slice(0, D-1)});
|
228 |
+
out += (dx) * (1 - dy) * corr.index({Slice(), Slice(), Slice(0, D-1), Slice(1, D-0)});
|
229 |
+
out += (1 - dx) * (dy) * corr.index({Slice(), Slice(), Slice(1, D-0), Slice(0, D-1)});
|
230 |
+
out += (dx) * (dy) * corr.index({Slice(), Slice(), Slice(1, D-0), Slice(1, D-0)});
|
231 |
+
|
232 |
+
return { out.permute({0,1,3,2,4,5}) };
|
233 |
+
}
|
234 |
+
|
235 |
+
|
236 |
+
std::vector<torch::Tensor> corr_cuda_backward(
|
237 |
+
torch::Tensor fmap1,
|
238 |
+
torch::Tensor fmap2,
|
239 |
+
torch::Tensor coords,
|
240 |
+
torch::Tensor ii,
|
241 |
+
torch::Tensor jj,
|
242 |
+
torch::Tensor grad,
|
243 |
+
int radius)
|
244 |
+
{
|
245 |
+
const int B = coords.size(0);
|
246 |
+
const int M = coords.size(1);
|
247 |
+
|
248 |
+
const int H = coords.size(3);
|
249 |
+
const int W = coords.size(4);
|
250 |
+
const int D = 2 * radius + 2;
|
251 |
+
|
252 |
+
grad = grad.permute({0,1,3,2,4,5}).contiguous();
|
253 |
+
torch::Tensor x = coords.index({Slice(), Slice(), 0, None, None});
|
254 |
+
torch::Tensor y = coords.index({Slice(), Slice(), 1, None, None});
|
255 |
+
torch::Tensor dx = x - x.floor();
|
256 |
+
torch::Tensor dy = y - y.floor();
|
257 |
+
|
258 |
+
auto opts = torch::TensorOptions().dtype(torch::kFloat).device(torch::kCUDA);
|
259 |
+
torch::Tensor g1 = torch::zeros({B, M, D, D, H, W}, grad.options());
|
260 |
+
torch::Tensor g2 = torch::zeros({B, M, D, D, H, W}, grad.options());
|
261 |
+
torch::Tensor g3 = torch::zeros({B, M, D, D, H, W}, grad.options());
|
262 |
+
torch::Tensor g4 = torch::zeros({B, M, D, D, H, W}, grad.options());
|
263 |
+
|
264 |
+
g1.index_put_({Slice(), Slice(), Slice(0, D-1), Slice(0, D-1)}, (1 - dx) * (1 - dy) * grad);
|
265 |
+
g2.index_put_({Slice(), Slice(), Slice(0, D-1), Slice(1, D-0)}, (dx) * (1 - dy) * grad);
|
266 |
+
g3.index_put_({Slice(), Slice(), Slice(1, D-0), Slice(0, D-1)}, (1 - dx) * (dy) * grad);
|
267 |
+
g4.index_put_({Slice(), Slice(), Slice(1, D-0), Slice(1, D-0)}, (dx) * (dy) * grad);
|
268 |
+
|
269 |
+
torch::Tensor corr_grad = g1 + g2 + g3 + g4;
|
270 |
+
auto fmap1_grad = torch::zeros_like(fmap1);
|
271 |
+
auto fmap2_grad = torch::zeros_like(fmap2);
|
272 |
+
|
273 |
+
AT_DISPATCH_FLOATING_TYPES_AND_HALF(fmap1.type(), "corr_backward_kernel", ([&] {
|
274 |
+
corr_backward_kernel<scalar_t><<<BLOCKS(B * M * H * W * D * D), THREADS>>>(radius,
|
275 |
+
fmap1.packed_accessor32<scalar_t,5,torch::RestrictPtrTraits>(),
|
276 |
+
fmap2.packed_accessor32<scalar_t,5,torch::RestrictPtrTraits>(),
|
277 |
+
coords.packed_accessor32<float,5,torch::RestrictPtrTraits>(),
|
278 |
+
ii.packed_accessor32<long,1,torch::RestrictPtrTraits>(),
|
279 |
+
jj.packed_accessor32<long,1,torch::RestrictPtrTraits>(),
|
280 |
+
corr_grad.packed_accessor32<float,6,torch::RestrictPtrTraits>(),
|
281 |
+
fmap1_grad.packed_accessor32<scalar_t,5,torch::RestrictPtrTraits>(),
|
282 |
+
fmap2_grad.packed_accessor32<scalar_t,5,torch::RestrictPtrTraits>());
|
283 |
+
}));
|
284 |
+
|
285 |
+
return {fmap1_grad, fmap2_grad};
|
286 |
+
}
|
287 |
+
|
288 |
+
std::vector<torch::Tensor> patchify_cuda_forward(
|
289 |
+
torch::Tensor net, torch::Tensor coords, int radius)
|
290 |
+
{
|
291 |
+
const int B = coords.size(0);
|
292 |
+
const int M = coords.size(1);
|
293 |
+
const int C = net.size(1);
|
294 |
+
const int D = 2 * radius + 2;
|
295 |
+
|
296 |
+
auto opts = net.options();
|
297 |
+
auto patches = torch::zeros({B, M, C, D, D}, opts);
|
298 |
+
|
299 |
+
AT_DISPATCH_FLOATING_TYPES_AND_HALF(net.type(), "patchify_forward_kernel", ([&] {
|
300 |
+
patchify_forward_kernel<scalar_t><<<BLOCKS(B * M * D * D), THREADS>>>(radius,
|
301 |
+
net.packed_accessor32<scalar_t,4,torch::RestrictPtrTraits>(),
|
302 |
+
coords.packed_accessor32<float,3,torch::RestrictPtrTraits>(),
|
303 |
+
patches.packed_accessor32<scalar_t,5,torch::RestrictPtrTraits>());
|
304 |
+
}));
|
305 |
+
|
306 |
+
return { patches };
|
307 |
+
}
|
308 |
+
|
309 |
+
|
310 |
+
std::vector<torch::Tensor> patchify_cuda_backward(
|
311 |
+
torch::Tensor net,
|
312 |
+
torch::Tensor coords,
|
313 |
+
torch::Tensor gradient,
|
314 |
+
int radius)
|
315 |
+
{
|
316 |
+
const int B = coords.size(0);
|
317 |
+
const int M = coords.size(1);
|
318 |
+
const int C = net.size(1);
|
319 |
+
const int H = net.size(2);
|
320 |
+
const int W = net.size(3);
|
321 |
+
const int D = 2 * radius + 2;
|
322 |
+
|
323 |
+
torch::Tensor net_gradient = torch::zeros_like(net);
|
324 |
+
|
325 |
+
AT_DISPATCH_FLOATING_TYPES_AND_HALF(net.type(), "patchify_backward_kernel", ([&] {
|
326 |
+
patchify_backward_kernel<scalar_t><<<BLOCKS(B * M * D * D), THREADS>>>(radius,
|
327 |
+
gradient.packed_accessor32<scalar_t,5,torch::RestrictPtrTraits>(),
|
328 |
+
coords.packed_accessor32<float,3,torch::RestrictPtrTraits>(),
|
329 |
+
net_gradient.packed_accessor32<scalar_t,4,torch::RestrictPtrTraits>());
|
330 |
+
}));
|
331 |
+
|
332 |
+
return { net_gradient };
|
333 |
+
}
|
third-party/DPVO/dpvo/ba.py
ADDED
@@ -0,0 +1,182 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import torch
|
2 |
+
from torch_scatter import scatter_sum
|
3 |
+
|
4 |
+
from . import fastba
|
5 |
+
from . import lietorch
|
6 |
+
from .lietorch import SE3
|
7 |
+
|
8 |
+
from .utils import Timer
|
9 |
+
|
10 |
+
from . import projective_ops as pops
|
11 |
+
|
12 |
+
class CholeskySolver(torch.autograd.Function):
|
13 |
+
@staticmethod
|
14 |
+
def forward(ctx, H, b):
|
15 |
+
# don't crash training if cholesky decomp fails
|
16 |
+
U, info = torch.linalg.cholesky_ex(H)
|
17 |
+
|
18 |
+
if torch.any(info):
|
19 |
+
ctx.failed = True
|
20 |
+
return torch.zeros_like(b)
|
21 |
+
|
22 |
+
xs = torch.cholesky_solve(b, U)
|
23 |
+
ctx.save_for_backward(U, xs)
|
24 |
+
ctx.failed = False
|
25 |
+
|
26 |
+
return xs
|
27 |
+
|
28 |
+
@staticmethod
|
29 |
+
def backward(ctx, grad_x):
|
30 |
+
if ctx.failed:
|
31 |
+
return None, None
|
32 |
+
|
33 |
+
U, xs = ctx.saved_tensors
|
34 |
+
dz = torch.cholesky_solve(grad_x, U)
|
35 |
+
dH = -torch.matmul(xs, dz.transpose(-1,-2))
|
36 |
+
|
37 |
+
return dH, dz
|
38 |
+
|
39 |
+
# utility functions for scattering ops
|
40 |
+
def safe_scatter_add_mat(A, ii, jj, n, m):
|
41 |
+
v = (ii >= 0) & (jj >= 0) & (ii < n) & (jj < m)
|
42 |
+
return scatter_sum(A[:,v], ii[v]*m + jj[v], dim=1, dim_size=n*m)
|
43 |
+
|
44 |
+
def safe_scatter_add_vec(b, ii, n):
|
45 |
+
v = (ii >= 0) & (ii < n)
|
46 |
+
return scatter_sum(b[:,v], ii[v], dim=1, dim_size=n)
|
47 |
+
|
48 |
+
# apply retraction operator to inv-depth maps
|
49 |
+
def disp_retr(disps, dz, ii):
|
50 |
+
ii = ii.to(device=dz.device)
|
51 |
+
return disps + scatter_sum(dz, ii, dim=1, dim_size=disps.shape[1])
|
52 |
+
|
53 |
+
# apply retraction operator to poses
|
54 |
+
def pose_retr(poses, dx, ii):
|
55 |
+
ii = ii.to(device=dx.device)
|
56 |
+
return poses.retr(scatter_sum(dx, ii, dim=1, dim_size=poses.shape[1]))
|
57 |
+
|
58 |
+
def block_matmul(A, B):
|
59 |
+
""" block matrix multiply """
|
60 |
+
b, n1, m1, p1, q1 = A.shape
|
61 |
+
b, n2, m2, p2, q2 = B.shape
|
62 |
+
A = A.permute(0, 1, 3, 2, 4).reshape(b, n1*p1, m1*q1)
|
63 |
+
B = B.permute(0, 1, 3, 2, 4).reshape(b, n2*p2, m2*q2)
|
64 |
+
return torch.matmul(A, B).reshape(b, n1, p1, m2, q2).permute(0, 1, 3, 2, 4)
|
65 |
+
|
66 |
+
def block_solve(A, B, ep=1.0, lm=1e-4):
|
67 |
+
""" block matrix solve """
|
68 |
+
b, n1, m1, p1, q1 = A.shape
|
69 |
+
b, n2, m2, p2, q2 = B.shape
|
70 |
+
A = A.permute(0, 1, 3, 2, 4).reshape(b, n1*p1, m1*q1)
|
71 |
+
B = B.permute(0, 1, 3, 2, 4).reshape(b, n2*p2, m2*q2)
|
72 |
+
|
73 |
+
A = A + (ep + lm * A) * torch.eye(n1*p1, device=A.device)
|
74 |
+
|
75 |
+
X = CholeskySolver.apply(A, B)
|
76 |
+
return X.reshape(b, n1, p1, m2, q2).permute(0, 1, 3, 2, 4)
|
77 |
+
|
78 |
+
|
79 |
+
def block_show(A):
|
80 |
+
import matplotlib.pyplot as plt
|
81 |
+
b, n1, m1, p1, q1 = A.shape
|
82 |
+
A = A.permute(0, 1, 3, 2, 4).reshape(b, n1*p1, m1*q1)
|
83 |
+
plt.imshow(A[0].detach().cpu().numpy())
|
84 |
+
plt.show()
|
85 |
+
|
86 |
+
def BA(poses, patches, intrinsics, targets, weights, lmbda, ii, jj, kk, bounds, ep=100.0, PRINT=False, fixedp=1, structure_only=False):
|
87 |
+
""" bundle adjustment """
|
88 |
+
|
89 |
+
b = 1
|
90 |
+
n = max(ii.max().item(), jj.max().item()) + 1
|
91 |
+
|
92 |
+
coords, v, (Ji, Jj, Jz) = \
|
93 |
+
pops.transform(poses, patches, intrinsics, ii, jj, kk, jacobian=True)
|
94 |
+
|
95 |
+
p = coords.shape[3]
|
96 |
+
r = targets - coords[...,p//2,p//2,:]
|
97 |
+
|
98 |
+
v *= (r.norm(dim=-1) < 250).float()
|
99 |
+
|
100 |
+
in_bounds = \
|
101 |
+
(coords[...,p//2,p//2,0] > bounds[0]) & \
|
102 |
+
(coords[...,p//2,p//2,1] > bounds[1]) & \
|
103 |
+
(coords[...,p//2,p//2,0] < bounds[2]) & \
|
104 |
+
(coords[...,p//2,p//2,1] < bounds[3])
|
105 |
+
|
106 |
+
v *= in_bounds.float()
|
107 |
+
|
108 |
+
if PRINT:
|
109 |
+
print((r * v[...,None]).norm(dim=-1).mean().item())
|
110 |
+
|
111 |
+
r = (v[...,None] * r).unsqueeze(dim=-1)
|
112 |
+
weights = (v[...,None] * weights).unsqueeze(dim=-1)
|
113 |
+
|
114 |
+
wJiT = (weights * Ji).transpose(2,3)
|
115 |
+
wJjT = (weights * Jj).transpose(2,3)
|
116 |
+
wJzT = (weights * Jz).transpose(2,3)
|
117 |
+
|
118 |
+
Bii = torch.matmul(wJiT, Ji)
|
119 |
+
Bij = torch.matmul(wJiT, Jj)
|
120 |
+
Bji = torch.matmul(wJjT, Ji)
|
121 |
+
Bjj = torch.matmul(wJjT, Jj)
|
122 |
+
|
123 |
+
Eik = torch.matmul(wJiT, Jz)
|
124 |
+
Ejk = torch.matmul(wJjT, Jz)
|
125 |
+
|
126 |
+
vi = torch.matmul(wJiT, r)
|
127 |
+
vj = torch.matmul(wJjT, r)
|
128 |
+
|
129 |
+
# fix first pose
|
130 |
+
ii = ii.clone()
|
131 |
+
jj = jj.clone()
|
132 |
+
|
133 |
+
n = n - fixedp
|
134 |
+
ii = ii - fixedp
|
135 |
+
jj = jj - fixedp
|
136 |
+
|
137 |
+
kx, kk = torch.unique(kk, return_inverse=True, sorted=True)
|
138 |
+
m = len(kx)
|
139 |
+
|
140 |
+
B = safe_scatter_add_mat(Bii, ii, ii, n, n).view(b, n, n, 6, 6) + \
|
141 |
+
safe_scatter_add_mat(Bij, ii, jj, n, n).view(b, n, n, 6, 6) + \
|
142 |
+
safe_scatter_add_mat(Bji, jj, ii, n, n).view(b, n, n, 6, 6) + \
|
143 |
+
safe_scatter_add_mat(Bjj, jj, jj, n, n).view(b, n, n, 6, 6)
|
144 |
+
|
145 |
+
E = safe_scatter_add_mat(Eik, ii, kk, n, m).view(b, n, m, 6, 1) + \
|
146 |
+
safe_scatter_add_mat(Ejk, jj, kk, n, m).view(b, n, m, 6, 1)
|
147 |
+
|
148 |
+
C = safe_scatter_add_vec(torch.matmul(wJzT, Jz), kk, m)
|
149 |
+
|
150 |
+
v = safe_scatter_add_vec(vi, ii, n).view(b, n, 1, 6, 1) + \
|
151 |
+
safe_scatter_add_vec(vj, jj, n).view(b, n, 1, 6, 1)
|
152 |
+
|
153 |
+
w = safe_scatter_add_vec(torch.matmul(wJzT, r), kk, m)
|
154 |
+
|
155 |
+
if isinstance(lmbda, torch.Tensor):
|
156 |
+
lmbda = lmbda.reshape(*C.shape)
|
157 |
+
|
158 |
+
Q = 1.0 / (C + lmbda)
|
159 |
+
|
160 |
+
### solve w/ schur complement ###
|
161 |
+
EQ = E * Q[:,None]
|
162 |
+
|
163 |
+
if structure_only or n == 0:
|
164 |
+
dZ = (Q * w).view(b, -1, 1, 1)
|
165 |
+
|
166 |
+
else:
|
167 |
+
S = B - block_matmul(EQ, E.permute(0,2,1,4,3))
|
168 |
+
y = v - block_matmul(EQ, w.unsqueeze(dim=2))
|
169 |
+
dX = block_solve(S, y, ep=ep, lm=1e-4)
|
170 |
+
|
171 |
+
dZ = Q * (w - block_matmul(E.permute(0,2,1,4,3), dX).squeeze(dim=-1))
|
172 |
+
dX = dX.view(b, -1, 6)
|
173 |
+
dZ = dZ.view(b, -1, 1, 1)
|
174 |
+
|
175 |
+
x, y, disps = patches.unbind(dim=2)
|
176 |
+
disps = disp_retr(disps, dZ, kx).clamp(min=1e-3, max=10.0)
|
177 |
+
patches = torch.stack([x, y, disps], dim=2)
|
178 |
+
|
179 |
+
if not structure_only and n > 0:
|
180 |
+
poses = pose_retr(poses, dX, fixedp + torch.arange(n))
|
181 |
+
|
182 |
+
return poses, patches
|
third-party/DPVO/dpvo/blocks.py
ADDED
@@ -0,0 +1,118 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import torch
|
2 |
+
import torch.nn as nn
|
3 |
+
import torch.nn.functional as F
|
4 |
+
|
5 |
+
import torch_scatter
|
6 |
+
|
7 |
+
class LayerNorm1D(nn.Module):
|
8 |
+
def __init__(self, dim):
|
9 |
+
super(LayerNorm1D, self).__init__()
|
10 |
+
self.norm = nn.LayerNorm(dim, eps=1e-4)
|
11 |
+
|
12 |
+
def forward(self, x):
|
13 |
+
return self.norm(x.transpose(1,2)).transpose(1,2)
|
14 |
+
|
15 |
+
class GatedResidual(nn.Module):
|
16 |
+
def __init__(self, dim):
|
17 |
+
super().__init__()
|
18 |
+
|
19 |
+
self.gate = nn.Sequential(
|
20 |
+
nn.Linear(dim, dim),
|
21 |
+
nn.Sigmoid())
|
22 |
+
|
23 |
+
self.res = nn.Sequential(
|
24 |
+
nn.Linear(dim, dim),
|
25 |
+
nn.ReLU(inplace=True),
|
26 |
+
nn.Linear(dim, dim))
|
27 |
+
|
28 |
+
def forward(self, x):
|
29 |
+
return x + self.gate(x) * self.res(x)
|
30 |
+
|
31 |
+
class SoftAgg(nn.Module):
|
32 |
+
def __init__(self, dim=512, expand=True):
|
33 |
+
super(SoftAgg, self).__init__()
|
34 |
+
self.dim = dim
|
35 |
+
self.expand = expand
|
36 |
+
self.f = nn.Linear(self.dim, self.dim)
|
37 |
+
self.g = nn.Linear(self.dim, self.dim)
|
38 |
+
self.h = nn.Linear(self.dim, self.dim)
|
39 |
+
|
40 |
+
def forward(self, x, ix):
|
41 |
+
_, jx = torch.unique(ix, return_inverse=True)
|
42 |
+
w = torch_scatter.scatter_softmax(self.g(x), jx, dim=1)
|
43 |
+
y = torch_scatter.scatter_sum(self.f(x) * w, jx, dim=1)
|
44 |
+
|
45 |
+
if self.expand:
|
46 |
+
return self.h(y)[:,jx]
|
47 |
+
|
48 |
+
return self.h(y)
|
49 |
+
|
50 |
+
class SoftAggBasic(nn.Module):
|
51 |
+
def __init__(self, dim=512, expand=True):
|
52 |
+
super(SoftAggBasic, self).__init__()
|
53 |
+
self.dim = dim
|
54 |
+
self.expand = expand
|
55 |
+
self.f = nn.Linear(self.dim, self.dim)
|
56 |
+
self.g = nn.Linear(self.dim, 1)
|
57 |
+
self.h = nn.Linear(self.dim, self.dim)
|
58 |
+
|
59 |
+
def forward(self, x, ix):
|
60 |
+
_, jx = torch.unique(ix, return_inverse=True)
|
61 |
+
w = torch_scatter.scatter_softmax(self.g(x), jx, dim=1)
|
62 |
+
y = torch_scatter.scatter_sum(self.f(x) * w, jx, dim=1)
|
63 |
+
|
64 |
+
if self.expand:
|
65 |
+
return self.h(y)[:,jx]
|
66 |
+
|
67 |
+
return self.h(y)
|
68 |
+
|
69 |
+
|
70 |
+
### Gradient Clipping and Zeroing Operations ###
|
71 |
+
|
72 |
+
GRAD_CLIP = 0.1
|
73 |
+
|
74 |
+
class GradClip(torch.autograd.Function):
|
75 |
+
@staticmethod
|
76 |
+
def forward(ctx, x):
|
77 |
+
return x
|
78 |
+
|
79 |
+
@staticmethod
|
80 |
+
def backward(ctx, grad_x):
|
81 |
+
grad_x = torch.where(torch.isnan(grad_x), torch.zeros_like(grad_x), grad_x)
|
82 |
+
return grad_x.clamp(min=-0.01, max=0.01)
|
83 |
+
|
84 |
+
class GradientClip(nn.Module):
|
85 |
+
def __init__(self):
|
86 |
+
super(GradientClip, self).__init__()
|
87 |
+
|
88 |
+
def forward(self, x):
|
89 |
+
return GradClip.apply(x)
|
90 |
+
|
91 |
+
class GradZero(torch.autograd.Function):
|
92 |
+
@staticmethod
|
93 |
+
def forward(ctx, x):
|
94 |
+
return x
|
95 |
+
|
96 |
+
@staticmethod
|
97 |
+
def backward(ctx, grad_x):
|
98 |
+
grad_x = torch.where(torch.isnan(grad_x), torch.zeros_like(grad_x), grad_x)
|
99 |
+
grad_x = torch.where(torch.abs(grad_x) > GRAD_CLIP, torch.zeros_like(grad_x), grad_x)
|
100 |
+
return grad_x
|
101 |
+
|
102 |
+
class GradientZero(nn.Module):
|
103 |
+
def __init__(self):
|
104 |
+
super(GradientZero, self).__init__()
|
105 |
+
|
106 |
+
def forward(self, x):
|
107 |
+
return GradZero.apply(x)
|
108 |
+
|
109 |
+
|
110 |
+
class GradMag(torch.autograd.Function):
|
111 |
+
@staticmethod
|
112 |
+
def forward(ctx, x):
|
113 |
+
return x
|
114 |
+
|
115 |
+
@staticmethod
|
116 |
+
def backward(ctx, grad_x):
|
117 |
+
print(grad_x.abs().mean())
|
118 |
+
return grad_x
|
third-party/DPVO/dpvo/config.py
ADDED
@@ -0,0 +1,38 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from yacs.config import CfgNode as CN
|
2 |
+
|
3 |
+
_C = CN()
|
4 |
+
|
5 |
+
# max number of keyframes
|
6 |
+
_C.BUFFER_SIZE = 4096
|
7 |
+
|
8 |
+
# bias patch selection towards high gradient regions?
|
9 |
+
_C.CENTROID_SEL_STRAT = 'RANDOM'
|
10 |
+
|
11 |
+
# VO config (increase for better accuracy)
|
12 |
+
_C.PATCHES_PER_FRAME = 80
|
13 |
+
_C.REMOVAL_WINDOW = 20
|
14 |
+
_C.OPTIMIZATION_WINDOW = 12
|
15 |
+
_C.PATCH_LIFETIME = 12
|
16 |
+
|
17 |
+
# threshold for keyframe removal
|
18 |
+
_C.KEYFRAME_INDEX = 4
|
19 |
+
_C.KEYFRAME_THRESH = 12.5
|
20 |
+
|
21 |
+
# camera motion model
|
22 |
+
_C.MOTION_MODEL = 'DAMPED_LINEAR'
|
23 |
+
_C.MOTION_DAMPING = 0.5
|
24 |
+
|
25 |
+
_C.MIXED_PRECISION = True
|
26 |
+
|
27 |
+
# Loop closure
|
28 |
+
_C.LOOP_CLOSURE = False
|
29 |
+
_C.BACKEND_THRESH = 64.0
|
30 |
+
_C.MAX_EDGE_AGE = 1000
|
31 |
+
_C.GLOBAL_OPT_FREQ = 15
|
32 |
+
|
33 |
+
# Classic loop closure
|
34 |
+
_C.CLASSIC_LOOP_CLOSURE = False
|
35 |
+
_C.LOOP_CLOSE_WINDOW_SIZE = 3
|
36 |
+
_C.LOOP_RETR_THRESH = 0.04
|
37 |
+
|
38 |
+
cfg = _C
|
third-party/DPVO/dpvo/data_readers/__init__.py
ADDED
@@ -0,0 +1 @@
|
|
|
|
|
1 |
+
|