netgen-mesher 6.2.2504.post11.dev0__cp313-cp313-win_amd64.whl → 6.2.2506.post48.dev0__cp313-cp313-win_amd64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- netgen/__init__.pyi +3 -3
- netgen/cmake/NetgenConfig.cmake +10 -9
- netgen/config/__init__.pyi +8 -8
- netgen/config/config.py +7 -7
- netgen/config/config.pyi +8 -8
- netgen/include/core/archive.hpp +18 -3
- netgen/include/core/array.hpp +20 -4
- netgen/include/core/autodiff.hpp +9 -11
- netgen/include/core/autodiffdiff.hpp +0 -2
- netgen/include/core/bitarray.hpp +1 -1
- netgen/include/core/flags.hpp +1 -1
- netgen/include/core/hashtable.hpp +1 -1
- netgen/include/core/memtracer.hpp +7 -7
- netgen/include/core/ngcore.hpp +5 -0
- netgen/include/core/ngcore_api.hpp +11 -0
- netgen/include/core/paje_trace.hpp +9 -8
- netgen/include/core/profiler.hpp +5 -5
- netgen/include/core/register_archive.hpp +8 -0
- netgen/include/core/simd.hpp +69 -1
- netgen/include/core/simd_arm64.hpp +205 -1
- netgen/include/core/simd_avx.hpp +72 -4
- netgen/include/core/simd_avx512.hpp +9 -0
- netgen/include/core/simd_generic.hpp +274 -8
- netgen/include/core/simd_math.hpp +178 -0
- netgen/include/core/simd_sse.hpp +11 -1
- netgen/include/core/statushandler.hpp +37 -0
- netgen/include/core/table.hpp +3 -2
- netgen/include/core/taskmanager.hpp +34 -1
- netgen/include/core/utils.hpp +3 -8
- netgen/include/include/netgen_version.hpp +4 -4
- netgen/include/meshing/basegeom.hpp +1 -4
- netgen/include/meshing/global.hpp +0 -17
- netgen/include/meshing/hpref_tet.hpp +41 -0
- netgen/include/meshing/hprefinement.hpp +2 -0
- netgen/include/meshing/meshtype.hpp +2 -1
- netgen/include/meshing/msghandler.hpp +9 -6
- netgen/include/meshing/topology.hpp +2 -2
- netgen/include/nginterface.h +3 -2
- netgen/include/occ/occ_utils.hpp +26 -0
- netgen/include/occ/occgeom.hpp +8 -0
- netgen/include/pybind11/attr.h +40 -8
- netgen/include/pybind11/buffer_info.h +14 -14
- netgen/include/pybind11/cast.h +553 -29
- netgen/include/pybind11/chrono.h +4 -1
- netgen/include/pybind11/conduit/README.txt +15 -0
- netgen/include/pybind11/conduit/pybind11_conduit_v1.h +116 -0
- netgen/include/pybind11/conduit/pybind11_platform_abi_id.h +87 -0
- netgen/include/pybind11/conduit/wrap_include_python_h.h +72 -0
- netgen/include/pybind11/critical_section.h +56 -0
- netgen/include/pybind11/detail/class.h +172 -97
- netgen/include/pybind11/detail/common.h +270 -189
- netgen/include/pybind11/detail/cpp_conduit.h +75 -0
- netgen/include/pybind11/detail/descr.h +55 -0
- netgen/include/pybind11/detail/dynamic_raw_ptr_cast_if_possible.h +39 -0
- netgen/include/pybind11/detail/exception_translation.h +71 -0
- netgen/include/pybind11/detail/function_record_pyobject.h +191 -0
- netgen/include/pybind11/detail/init.h +113 -9
- netgen/include/pybind11/detail/internals.h +479 -344
- netgen/include/pybind11/detail/native_enum_data.h +209 -0
- netgen/include/pybind11/detail/pybind11_namespace_macros.h +82 -0
- netgen/include/pybind11/detail/struct_smart_holder.h +378 -0
- netgen/include/pybind11/detail/type_caster_base.h +506 -133
- netgen/include/pybind11/detail/using_smart_holder.h +22 -0
- netgen/include/pybind11/detail/value_and_holder.h +90 -0
- netgen/include/pybind11/eigen/matrix.h +19 -10
- netgen/include/pybind11/eigen/tensor.h +15 -11
- netgen/include/pybind11/embed.h +50 -46
- netgen/include/pybind11/eval.h +11 -6
- netgen/include/pybind11/functional.h +58 -49
- netgen/include/pybind11/gil.h +34 -82
- netgen/include/pybind11/gil_safe_call_once.h +12 -1
- netgen/include/pybind11/gil_simple.h +37 -0
- netgen/include/pybind11/native_enum.h +67 -0
- netgen/include/pybind11/numpy.h +272 -93
- netgen/include/pybind11/pybind11.h +947 -265
- netgen/include/pybind11/pytypes.h +127 -21
- netgen/include/pybind11/stl/filesystem.h +23 -25
- netgen/include/pybind11/stl.h +277 -59
- netgen/include/pybind11/stl_bind.h +42 -7
- netgen/include/pybind11/subinterpreter.h +299 -0
- netgen/include/pybind11/trampoline_self_life_support.h +65 -0
- netgen/include/pybind11/typing.h +177 -4
- netgen/include/pybind11/warnings.h +75 -0
- netgen/include/visualization/mvdraw.hpp +48 -12
- netgen/include/visualization/vssolution.hpp +3 -1
- netgen/lib/libnggui.lib +0 -0
- netgen/lib/ngcore.lib +0 -0
- netgen/lib/nglib.lib +0 -0
- netgen/libnggui.dll +0 -0
- netgen/libngguipy.pyd +0 -0
- netgen/libngpy/_NgOCC.pyi +224 -139
- netgen/libngpy/_csg.pyi +26 -26
- netgen/libngpy/_geom2d.pyi +34 -25
- netgen/libngpy/_meshing.pyi +262 -111
- netgen/libngpy/_stl.pyi +3 -4
- netgen/libngpy.pyd +0 -0
- netgen/ngcore.dll +0 -0
- netgen/nglib.dll +0 -0
- netgen/read_gmsh.py +41 -0
- netgen/togl.dll +0 -0
- netgen/version.py +1 -1
- netgen/webgui.py +38 -2
- {netgen_mesher-6.2.2504.post11.dev0.dist-info → netgen_mesher-6.2.2506.post48.dev0.dist-info}/METADATA +2 -1
- {netgen_mesher-6.2.2504.post11.dev0.dist-info → netgen_mesher-6.2.2506.post48.dev0.dist-info}/RECORD +153 -132
- pyngcore/pyngcore.cp313-win_amd64.pyd +0 -0
- {netgen_mesher-6.2.2504.post11.dev0.data → netgen_mesher-6.2.2506.post48.dev0.data}/data/share/netgen/boundarycondition.geo +0 -0
- {netgen_mesher-6.2.2504.post11.dev0.data → netgen_mesher-6.2.2506.post48.dev0.data}/data/share/netgen/boxcyl.geo +0 -0
- {netgen_mesher-6.2.2504.post11.dev0.data → netgen_mesher-6.2.2506.post48.dev0.data}/data/share/netgen/circle_on_cube.geo +0 -0
- {netgen_mesher-6.2.2504.post11.dev0.data → netgen_mesher-6.2.2506.post48.dev0.data}/data/share/netgen/cone.geo +0 -0
- {netgen_mesher-6.2.2504.post11.dev0.data → netgen_mesher-6.2.2506.post48.dev0.data}/data/share/netgen/cube.geo +0 -0
- {netgen_mesher-6.2.2504.post11.dev0.data → netgen_mesher-6.2.2506.post48.dev0.data}/data/share/netgen/cubeandring.geo +0 -0
- {netgen_mesher-6.2.2504.post11.dev0.data → netgen_mesher-6.2.2506.post48.dev0.data}/data/share/netgen/cubeandspheres.geo +0 -0
- {netgen_mesher-6.2.2504.post11.dev0.data → netgen_mesher-6.2.2506.post48.dev0.data}/data/share/netgen/cubemcyl.geo +0 -0
- {netgen_mesher-6.2.2504.post11.dev0.data → netgen_mesher-6.2.2506.post48.dev0.data}/data/share/netgen/cubemsphere.geo +0 -0
- {netgen_mesher-6.2.2504.post11.dev0.data → netgen_mesher-6.2.2506.post48.dev0.data}/data/share/netgen/cylinder.geo +0 -0
- {netgen_mesher-6.2.2504.post11.dev0.data → netgen_mesher-6.2.2506.post48.dev0.data}/data/share/netgen/cylsphere.geo +0 -0
- {netgen_mesher-6.2.2504.post11.dev0.data → netgen_mesher-6.2.2506.post48.dev0.data}/data/share/netgen/doc/ng4.pdf +0 -0
- {netgen_mesher-6.2.2504.post11.dev0.data → netgen_mesher-6.2.2506.post48.dev0.data}/data/share/netgen/ellipsoid.geo +0 -0
- {netgen_mesher-6.2.2504.post11.dev0.data → netgen_mesher-6.2.2506.post48.dev0.data}/data/share/netgen/ellipticcyl.geo +0 -0
- {netgen_mesher-6.2.2504.post11.dev0.data → netgen_mesher-6.2.2506.post48.dev0.data}/data/share/netgen/extrusion.geo +0 -0
- {netgen_mesher-6.2.2504.post11.dev0.data → netgen_mesher-6.2.2506.post48.dev0.data}/data/share/netgen/fichera.geo +0 -0
- {netgen_mesher-6.2.2504.post11.dev0.data → netgen_mesher-6.2.2506.post48.dev0.data}/data/share/netgen/frame.step +0 -0
- {netgen_mesher-6.2.2504.post11.dev0.data → netgen_mesher-6.2.2506.post48.dev0.data}/data/share/netgen/hinge.stl +0 -0
- {netgen_mesher-6.2.2504.post11.dev0.data → netgen_mesher-6.2.2506.post48.dev0.data}/data/share/netgen/lshape3d.geo +0 -0
- {netgen_mesher-6.2.2504.post11.dev0.data → netgen_mesher-6.2.2506.post48.dev0.data}/data/share/netgen/manyholes.geo +0 -0
- {netgen_mesher-6.2.2504.post11.dev0.data → netgen_mesher-6.2.2506.post48.dev0.data}/data/share/netgen/manyholes2.geo +0 -0
- {netgen_mesher-6.2.2504.post11.dev0.data → netgen_mesher-6.2.2506.post48.dev0.data}/data/share/netgen/matrix.geo +0 -0
- {netgen_mesher-6.2.2504.post11.dev0.data → netgen_mesher-6.2.2506.post48.dev0.data}/data/share/netgen/ortho.geo +0 -0
- {netgen_mesher-6.2.2504.post11.dev0.data → netgen_mesher-6.2.2506.post48.dev0.data}/data/share/netgen/part1.stl +0 -0
- {netgen_mesher-6.2.2504.post11.dev0.data → netgen_mesher-6.2.2506.post48.dev0.data}/data/share/netgen/period.geo +0 -0
- {netgen_mesher-6.2.2504.post11.dev0.data → netgen_mesher-6.2.2506.post48.dev0.data}/data/share/netgen/py_tutorials/exportNeutral.py +0 -0
- {netgen_mesher-6.2.2504.post11.dev0.data → netgen_mesher-6.2.2506.post48.dev0.data}/data/share/netgen/py_tutorials/mesh.py +0 -0
- {netgen_mesher-6.2.2504.post11.dev0.data → netgen_mesher-6.2.2506.post48.dev0.data}/data/share/netgen/py_tutorials/shaft.geo +0 -0
- {netgen_mesher-6.2.2504.post11.dev0.data → netgen_mesher-6.2.2506.post48.dev0.data}/data/share/netgen/revolution.geo +0 -0
- {netgen_mesher-6.2.2504.post11.dev0.data → netgen_mesher-6.2.2506.post48.dev0.data}/data/share/netgen/screw.step +0 -0
- {netgen_mesher-6.2.2504.post11.dev0.data → netgen_mesher-6.2.2506.post48.dev0.data}/data/share/netgen/sculpture.geo +0 -0
- {netgen_mesher-6.2.2504.post11.dev0.data → netgen_mesher-6.2.2506.post48.dev0.data}/data/share/netgen/shaft.geo +0 -0
- {netgen_mesher-6.2.2504.post11.dev0.data → netgen_mesher-6.2.2506.post48.dev0.data}/data/share/netgen/shell.geo +0 -0
- {netgen_mesher-6.2.2504.post11.dev0.data → netgen_mesher-6.2.2506.post48.dev0.data}/data/share/netgen/sphere.geo +0 -0
- {netgen_mesher-6.2.2504.post11.dev0.data → netgen_mesher-6.2.2506.post48.dev0.data}/data/share/netgen/sphereincube.geo +0 -0
- {netgen_mesher-6.2.2504.post11.dev0.data → netgen_mesher-6.2.2506.post48.dev0.data}/data/share/netgen/square.in2d +0 -0
- {netgen_mesher-6.2.2504.post11.dev0.data → netgen_mesher-6.2.2506.post48.dev0.data}/data/share/netgen/squarecircle.in2d +0 -0
- {netgen_mesher-6.2.2504.post11.dev0.data → netgen_mesher-6.2.2506.post48.dev0.data}/data/share/netgen/squarehole.in2d +0 -0
- {netgen_mesher-6.2.2504.post11.dev0.data → netgen_mesher-6.2.2506.post48.dev0.data}/data/share/netgen/torus.geo +0 -0
- {netgen_mesher-6.2.2504.post11.dev0.data → netgen_mesher-6.2.2506.post48.dev0.data}/data/share/netgen/trafo.geo +0 -0
- {netgen_mesher-6.2.2504.post11.dev0.data → netgen_mesher-6.2.2506.post48.dev0.data}/data/share/netgen/twobricks.geo +0 -0
- {netgen_mesher-6.2.2504.post11.dev0.data → netgen_mesher-6.2.2506.post48.dev0.data}/data/share/netgen/twocubes.geo +0 -0
- {netgen_mesher-6.2.2504.post11.dev0.data → netgen_mesher-6.2.2506.post48.dev0.data}/data/share/netgen/twocyl.geo +0 -0
- {netgen_mesher-6.2.2504.post11.dev0.dist-info → netgen_mesher-6.2.2506.post48.dev0.dist-info}/AUTHORS +0 -0
- {netgen_mesher-6.2.2504.post11.dev0.dist-info → netgen_mesher-6.2.2506.post48.dev0.dist-info}/LICENSE +0 -0
- {netgen_mesher-6.2.2504.post11.dev0.dist-info → netgen_mesher-6.2.2506.post48.dev0.dist-info}/WHEEL +0 -0
- {netgen_mesher-6.2.2504.post11.dev0.dist-info → netgen_mesher-6.2.2506.post48.dev0.dist-info}/entry_points.txt +0 -0
- {netgen_mesher-6.2.2504.post11.dev0.dist-info → netgen_mesher-6.2.2506.post48.dev0.dist-info}/top_level.txt +0 -0
|
@@ -9,30 +9,36 @@
|
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
11
|
#pragma once
|
|
12
|
-
|
|
13
12
|
#include "detail/class.h"
|
|
13
|
+
#include "detail/dynamic_raw_ptr_cast_if_possible.h"
|
|
14
|
+
#include "detail/exception_translation.h"
|
|
15
|
+
#include "detail/function_record_pyobject.h"
|
|
14
16
|
#include "detail/init.h"
|
|
17
|
+
#include "detail/native_enum_data.h"
|
|
18
|
+
#include "detail/using_smart_holder.h"
|
|
15
19
|
#include "attr.h"
|
|
16
20
|
#include "gil.h"
|
|
17
21
|
#include "gil_safe_call_once.h"
|
|
18
22
|
#include "options.h"
|
|
23
|
+
#include "trampoline_self_life_support.h"
|
|
19
24
|
#include "typing.h"
|
|
20
25
|
|
|
26
|
+
#include <cassert>
|
|
21
27
|
#include <cstdlib>
|
|
22
28
|
#include <cstring>
|
|
23
29
|
#include <memory>
|
|
24
30
|
#include <new>
|
|
31
|
+
#include <stack>
|
|
25
32
|
#include <string>
|
|
26
33
|
#include <utility>
|
|
27
34
|
#include <vector>
|
|
28
35
|
|
|
29
|
-
#
|
|
30
|
-
|
|
31
|
-
#
|
|
32
|
-
|
|
33
|
-
# define PYBIND11_STD_LAUNDER
|
|
34
|
-
# define PYBIND11_HAS_STD_LAUNDER 0
|
|
36
|
+
// See PR #5448. This warning suppression is needed for the PYBIND11_OVERRIDE macro family.
|
|
37
|
+
// NOTE that this is NOT embedded in a push/pop pair because that is very difficult to achieve.
|
|
38
|
+
#if defined(__clang_major__) && __clang_major__ < 14
|
|
39
|
+
PYBIND11_WARNING_DISABLE_CLANG("-Wgnu-zero-variadic-macro-arguments")
|
|
35
40
|
#endif
|
|
41
|
+
|
|
36
42
|
#if defined(__GNUG__) && !defined(__clang__)
|
|
37
43
|
# include <cxxabi.h>
|
|
38
44
|
#endif
|
|
@@ -95,22 +101,145 @@ inline std::string replace_newlines_and_squash(const char *text) {
|
|
|
95
101
|
return result.substr(str_begin, str_range);
|
|
96
102
|
}
|
|
97
103
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
104
|
+
/* Generate a proper function signature */
|
|
105
|
+
inline std::string generate_function_signature(const char *type_caster_name_field,
|
|
106
|
+
detail::function_record *func_rec,
|
|
107
|
+
const std::type_info *const *types,
|
|
108
|
+
size_t &type_index,
|
|
109
|
+
size_t &arg_index) {
|
|
110
|
+
std::string signature;
|
|
111
|
+
bool is_starred = false;
|
|
112
|
+
// `is_return_value.top()` is true if we are currently inside the return type of the
|
|
113
|
+
// signature. Using `@^`/`@$` we can force types to be arg/return types while `@!` pops
|
|
114
|
+
// back to the previous state.
|
|
115
|
+
std::stack<bool> is_return_value({false});
|
|
116
|
+
// The following characters have special meaning in the signature parsing. Literals
|
|
117
|
+
// containing these are escaped with `!`.
|
|
118
|
+
std::string special_chars("!@%{}-");
|
|
119
|
+
for (const auto *pc = type_caster_name_field; *pc != '\0'; ++pc) {
|
|
120
|
+
const auto c = *pc;
|
|
121
|
+
if (c == '{') {
|
|
122
|
+
// Write arg name for everything except *args and **kwargs.
|
|
123
|
+
is_starred = *(pc + 1) == '*';
|
|
124
|
+
if (is_starred) {
|
|
125
|
+
continue;
|
|
126
|
+
}
|
|
127
|
+
// Separator for keyword-only arguments, placed before the kw
|
|
128
|
+
// arguments start (unless we are already putting an *args)
|
|
129
|
+
if (!func_rec->has_args && arg_index == func_rec->nargs_pos) {
|
|
130
|
+
signature += "*, ";
|
|
131
|
+
}
|
|
132
|
+
if (arg_index < func_rec->args.size() && func_rec->args[arg_index].name) {
|
|
133
|
+
signature += func_rec->args[arg_index].name;
|
|
134
|
+
} else if (arg_index == 0 && func_rec->is_method) {
|
|
135
|
+
signature += "self";
|
|
136
|
+
} else {
|
|
137
|
+
signature += "arg" + std::to_string(arg_index - (func_rec->is_method ? 1 : 0));
|
|
138
|
+
}
|
|
139
|
+
signature += ": ";
|
|
140
|
+
} else if (c == '}') {
|
|
141
|
+
// Write default value if available.
|
|
142
|
+
if (!is_starred && arg_index < func_rec->args.size()
|
|
143
|
+
&& func_rec->args[arg_index].descr) {
|
|
144
|
+
signature += " = ";
|
|
145
|
+
signature += detail::replace_newlines_and_squash(func_rec->args[arg_index].descr);
|
|
146
|
+
}
|
|
147
|
+
// Separator for positional-only arguments (placed after the
|
|
148
|
+
// argument, rather than before like *
|
|
149
|
+
if (func_rec->nargs_pos_only > 0 && (arg_index + 1) == func_rec->nargs_pos_only) {
|
|
150
|
+
signature += ", /";
|
|
151
|
+
}
|
|
152
|
+
if (!is_starred) {
|
|
153
|
+
arg_index++;
|
|
154
|
+
}
|
|
155
|
+
} else if (c == '%') {
|
|
156
|
+
const std::type_info *t = types[type_index++];
|
|
157
|
+
if (!t) {
|
|
158
|
+
pybind11_fail("Internal error while parsing type signature (1)");
|
|
159
|
+
}
|
|
160
|
+
if (auto *tinfo = detail::get_type_info(*t)) {
|
|
161
|
+
handle th((PyObject *) tinfo->type);
|
|
162
|
+
signature += th.attr("__module__").cast<std::string>() + "."
|
|
163
|
+
+ th.attr("__qualname__").cast<std::string>();
|
|
164
|
+
} else if (auto th = detail::global_internals_native_enum_type_map_get_item(*t)) {
|
|
165
|
+
signature += th.attr("__module__").cast<std::string>() + "."
|
|
166
|
+
+ th.attr("__qualname__").cast<std::string>();
|
|
167
|
+
} else if (func_rec->is_new_style_constructor && arg_index == 0) {
|
|
168
|
+
// A new-style `__init__` takes `self` as `value_and_holder`.
|
|
169
|
+
// Rewrite it to the proper class type.
|
|
170
|
+
signature += func_rec->scope.attr("__module__").cast<std::string>() + "."
|
|
171
|
+
+ func_rec->scope.attr("__qualname__").cast<std::string>();
|
|
172
|
+
} else {
|
|
173
|
+
signature += detail::quote_cpp_type_name(detail::clean_type_id(t->name()));
|
|
174
|
+
}
|
|
175
|
+
} else if (c == '!' && special_chars.find(*(pc + 1)) != std::string::npos) {
|
|
176
|
+
// typing::Literal escapes special characters with !
|
|
177
|
+
signature += *++pc;
|
|
178
|
+
} else if (c == '@') {
|
|
179
|
+
// `@^ ... @!` and `@$ ... @!` are used to force arg/return value type (see
|
|
180
|
+
// typing::Callable/detail::arg_descr/detail::return_descr)
|
|
181
|
+
if (*(pc + 1) == '^') {
|
|
182
|
+
is_return_value.emplace(false);
|
|
183
|
+
++pc;
|
|
184
|
+
continue;
|
|
185
|
+
}
|
|
186
|
+
if (*(pc + 1) == '$') {
|
|
187
|
+
is_return_value.emplace(true);
|
|
188
|
+
++pc;
|
|
189
|
+
continue;
|
|
190
|
+
}
|
|
191
|
+
if (*(pc + 1) == '!') {
|
|
192
|
+
is_return_value.pop();
|
|
193
|
+
++pc;
|
|
194
|
+
continue;
|
|
195
|
+
}
|
|
196
|
+
// Handle types that differ depending on whether they appear
|
|
197
|
+
// in an argument or a return value position (see io_name<text1, text2>).
|
|
198
|
+
// For named arguments (py::arg()) with noconvert set, return value type is used.
|
|
199
|
+
++pc;
|
|
200
|
+
if (!is_return_value.top()
|
|
201
|
+
&& (!(arg_index < func_rec->args.size() && !func_rec->args[arg_index].convert))) {
|
|
202
|
+
while (*pc != '\0' && *pc != '@') {
|
|
203
|
+
signature += *pc++;
|
|
204
|
+
}
|
|
205
|
+
if (*pc == '@') {
|
|
206
|
+
++pc;
|
|
207
|
+
}
|
|
208
|
+
while (*pc != '\0' && *pc != '@') {
|
|
209
|
+
++pc;
|
|
210
|
+
}
|
|
211
|
+
} else {
|
|
212
|
+
while (*pc != '\0' && *pc != '@') {
|
|
213
|
+
++pc;
|
|
214
|
+
}
|
|
215
|
+
if (*pc == '@') {
|
|
216
|
+
++pc;
|
|
217
|
+
}
|
|
218
|
+
while (*pc != '\0' && *pc != '@') {
|
|
219
|
+
signature += *pc++;
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
} else {
|
|
223
|
+
if (c == '-' && *(pc + 1) == '>') {
|
|
224
|
+
is_return_value.emplace(true);
|
|
225
|
+
}
|
|
226
|
+
signature += c;
|
|
111
227
|
}
|
|
112
228
|
}
|
|
113
|
-
return
|
|
229
|
+
return signature;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
template <typename T>
|
|
233
|
+
inline std::string generate_type_signature() {
|
|
234
|
+
static constexpr auto caster_name_field = make_caster<T>::name;
|
|
235
|
+
PYBIND11_DESCR_CONSTEXPR auto descr_types = decltype(caster_name_field)::types();
|
|
236
|
+
// Create a default function_record to ensure the function signature has the proper
|
|
237
|
+
// configuration e.g. no_convert.
|
|
238
|
+
auto func_rec = function_record();
|
|
239
|
+
size_t type_index = 0;
|
|
240
|
+
size_t arg_index = 0;
|
|
241
|
+
return generate_function_signature(
|
|
242
|
+
caster_name_field.text, &func_rec, descr_types.data(), type_index, arg_index);
|
|
114
243
|
}
|
|
115
244
|
|
|
116
245
|
#if defined(_MSC_VER)
|
|
@@ -152,7 +281,7 @@ public:
|
|
|
152
281
|
cpp_function(Return (Class::*f)(Arg...), const Extra &...extra) {
|
|
153
282
|
initialize(
|
|
154
283
|
[f](Class *c, Arg... args) -> Return { return (c->*f)(std::forward<Arg>(args)...); },
|
|
155
|
-
(Return(*)(Class *, Arg...)) nullptr,
|
|
284
|
+
(Return (*)(Class *, Arg...)) nullptr,
|
|
156
285
|
extra...);
|
|
157
286
|
}
|
|
158
287
|
|
|
@@ -164,7 +293,7 @@ public:
|
|
|
164
293
|
cpp_function(Return (Class::*f)(Arg...) &, const Extra &...extra) {
|
|
165
294
|
initialize(
|
|
166
295
|
[f](Class *c, Arg... args) -> Return { return (c->*f)(std::forward<Arg>(args)...); },
|
|
167
|
-
(Return(*)(Class *, Arg...)) nullptr,
|
|
296
|
+
(Return (*)(Class *, Arg...)) nullptr,
|
|
168
297
|
extra...);
|
|
169
298
|
}
|
|
170
299
|
|
|
@@ -174,7 +303,7 @@ public:
|
|
|
174
303
|
cpp_function(Return (Class::*f)(Arg...) const, const Extra &...extra) {
|
|
175
304
|
initialize([f](const Class *c,
|
|
176
305
|
Arg... args) -> Return { return (c->*f)(std::forward<Arg>(args)...); },
|
|
177
|
-
(Return(*)(const Class *, Arg...)) nullptr,
|
|
306
|
+
(Return (*)(const Class *, Arg...)) nullptr,
|
|
178
307
|
extra...);
|
|
179
308
|
}
|
|
180
309
|
|
|
@@ -186,7 +315,7 @@ public:
|
|
|
186
315
|
cpp_function(Return (Class::*f)(Arg...) const &, const Extra &...extra) {
|
|
187
316
|
initialize([f](const Class *c,
|
|
188
317
|
Arg... args) -> Return { return (c->*f)(std::forward<Arg>(args)...); },
|
|
189
|
-
(Return(*)(const Class *, Arg...)) nullptr,
|
|
318
|
+
(Return (*)(const Class *, Arg...)) nullptr,
|
|
190
319
|
extra...);
|
|
191
320
|
}
|
|
192
321
|
|
|
@@ -213,6 +342,10 @@ protected:
|
|
|
213
342
|
using namespace detail;
|
|
214
343
|
struct capture {
|
|
215
344
|
remove_reference_t<Func> f;
|
|
345
|
+
|
|
346
|
+
static capture *from_data(void **data) {
|
|
347
|
+
return PYBIND11_STD_LAUNDER(reinterpret_cast<capture *>(data));
|
|
348
|
+
}
|
|
216
349
|
};
|
|
217
350
|
|
|
218
351
|
/* Store the function including any extra state it might have (e.g. a lambda capture
|
|
@@ -232,7 +365,7 @@ protected:
|
|
|
232
365
|
PYBIND11_WARNING_DISABLE_GCC("-Wplacement-new")
|
|
233
366
|
#endif
|
|
234
367
|
|
|
235
|
-
new ((
|
|
368
|
+
new (capture::from_data(rec->data)) capture{std::forward<Func>(f)};
|
|
236
369
|
|
|
237
370
|
#if !PYBIND11_HAS_STD_LAUNDER
|
|
238
371
|
PYBIND11_WARNING_DISABLE_GCC("-Wstrict-aliasing")
|
|
@@ -242,8 +375,8 @@ protected:
|
|
|
242
375
|
// a significant refactoring it's "impossible" to solve.
|
|
243
376
|
if (!std::is_trivially_destructible<capture>::value) {
|
|
244
377
|
rec->free_data = [](function_record *r) {
|
|
245
|
-
auto data =
|
|
246
|
-
(void) data;
|
|
378
|
+
auto data = capture::from_data(r->data);
|
|
379
|
+
(void) data; // suppress "unused variable" warnings
|
|
247
380
|
data->~capture();
|
|
248
381
|
};
|
|
249
382
|
}
|
|
@@ -319,9 +452,20 @@ protected:
|
|
|
319
452
|
constexpr bool has_kw_only_args = any_of<std::is_same<kw_only, Extra>...>::value,
|
|
320
453
|
has_pos_only_args = any_of<std::is_same<pos_only, Extra>...>::value,
|
|
321
454
|
has_arg_annotations = any_of<is_keyword<Extra>...>::value;
|
|
455
|
+
constexpr bool has_is_method = any_of<std::is_same<is_method, Extra>...>::value;
|
|
456
|
+
// The implicit `self` argument is not present and not counted in method definitions.
|
|
457
|
+
constexpr bool has_args = cast_in::args_pos >= 0;
|
|
458
|
+
constexpr bool is_method_with_self_arg_only = has_is_method && !has_args;
|
|
322
459
|
static_assert(has_arg_annotations || !has_kw_only_args,
|
|
323
460
|
"py::kw_only requires the use of argument annotations");
|
|
324
|
-
static_assert(
|
|
461
|
+
static_assert(((/* Need `py::arg("arg_name")` annotation in function/method. */
|
|
462
|
+
has_arg_annotations)
|
|
463
|
+
|| (/* Allow methods with no arguments `def method(self, /): ...`.
|
|
464
|
+
* A method has at least one argument `self`. There can be no
|
|
465
|
+
* `py::arg` annotation. E.g. `class.def("method", py::pos_only())`.
|
|
466
|
+
*/
|
|
467
|
+
is_method_with_self_arg_only))
|
|
468
|
+
|| !has_pos_only_args,
|
|
325
469
|
"py::pos_only requires the use of argument annotations (for docstrings "
|
|
326
470
|
"and aligning the annotations to the argument)");
|
|
327
471
|
|
|
@@ -349,6 +493,8 @@ protected:
|
|
|
349
493
|
using FunctionType = Return (*)(Args...);
|
|
350
494
|
constexpr bool is_function_ptr
|
|
351
495
|
= std::is_convertible<Func, FunctionType>::value && sizeof(capture) == sizeof(void *);
|
|
496
|
+
PYBIND11_ENSURE_PRECONDITION_FOR_FUNCTIONAL_H_PERFORMANCE_OPTIMIZATIONS(
|
|
497
|
+
!is_function_ptr || std::is_standard_layout<capture>::value);
|
|
352
498
|
if (is_function_ptr) {
|
|
353
499
|
rec->is_stateless = true;
|
|
354
500
|
rec->data[1]
|
|
@@ -437,67 +583,9 @@ protected:
|
|
|
437
583
|
}
|
|
438
584
|
#endif
|
|
439
585
|
|
|
440
|
-
/* Generate a proper function signature */
|
|
441
|
-
std::string signature;
|
|
442
586
|
size_t type_index = 0, arg_index = 0;
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
const auto c = *pc;
|
|
446
|
-
|
|
447
|
-
if (c == '{') {
|
|
448
|
-
// Write arg name for everything except *args and **kwargs.
|
|
449
|
-
is_starred = *(pc + 1) == '*';
|
|
450
|
-
if (is_starred) {
|
|
451
|
-
continue;
|
|
452
|
-
}
|
|
453
|
-
// Separator for keyword-only arguments, placed before the kw
|
|
454
|
-
// arguments start (unless we are already putting an *args)
|
|
455
|
-
if (!rec->has_args && arg_index == rec->nargs_pos) {
|
|
456
|
-
signature += "*, ";
|
|
457
|
-
}
|
|
458
|
-
if (arg_index < rec->args.size() && rec->args[arg_index].name) {
|
|
459
|
-
signature += rec->args[arg_index].name;
|
|
460
|
-
} else if (arg_index == 0 && rec->is_method) {
|
|
461
|
-
signature += "self";
|
|
462
|
-
} else {
|
|
463
|
-
signature += "arg" + std::to_string(arg_index - (rec->is_method ? 1 : 0));
|
|
464
|
-
}
|
|
465
|
-
signature += ": ";
|
|
466
|
-
} else if (c == '}') {
|
|
467
|
-
// Write default value if available.
|
|
468
|
-
if (!is_starred && arg_index < rec->args.size() && rec->args[arg_index].descr) {
|
|
469
|
-
signature += " = ";
|
|
470
|
-
signature += detail::replace_newlines_and_squash(rec->args[arg_index].descr);
|
|
471
|
-
}
|
|
472
|
-
// Separator for positional-only arguments (placed after the
|
|
473
|
-
// argument, rather than before like *
|
|
474
|
-
if (rec->nargs_pos_only > 0 && (arg_index + 1) == rec->nargs_pos_only) {
|
|
475
|
-
signature += ", /";
|
|
476
|
-
}
|
|
477
|
-
if (!is_starred) {
|
|
478
|
-
arg_index++;
|
|
479
|
-
}
|
|
480
|
-
} else if (c == '%') {
|
|
481
|
-
const std::type_info *t = types[type_index++];
|
|
482
|
-
if (!t) {
|
|
483
|
-
pybind11_fail("Internal error while parsing type signature (1)");
|
|
484
|
-
}
|
|
485
|
-
if (auto *tinfo = detail::get_type_info(*t)) {
|
|
486
|
-
handle th((PyObject *) tinfo->type);
|
|
487
|
-
signature += th.attr("__module__").cast<std::string>() + "."
|
|
488
|
-
+ th.attr("__qualname__").cast<std::string>();
|
|
489
|
-
} else if (rec->is_new_style_constructor && arg_index == 0) {
|
|
490
|
-
// A new-style `__init__` takes `self` as `value_and_holder`.
|
|
491
|
-
// Rewrite it to the proper class type.
|
|
492
|
-
signature += rec->scope.attr("__module__").cast<std::string>() + "."
|
|
493
|
-
+ rec->scope.attr("__qualname__").cast<std::string>();
|
|
494
|
-
} else {
|
|
495
|
-
signature += detail::quote_cpp_type_name(detail::clean_type_id(t->name()));
|
|
496
|
-
}
|
|
497
|
-
} else {
|
|
498
|
-
signature += c;
|
|
499
|
-
}
|
|
500
|
-
}
|
|
587
|
+
std::string signature
|
|
588
|
+
= detail::generate_function_signature(text, rec, types, type_index, arg_index);
|
|
501
589
|
|
|
502
590
|
if (arg_index != args - rec->has_args - rec->has_kwargs || types[type_index] != nullptr) {
|
|
503
591
|
pybind11_fail("Internal error while parsing type signature (2)");
|
|
@@ -515,20 +603,15 @@ protected:
|
|
|
515
603
|
if (rec->sibling) {
|
|
516
604
|
if (PyCFunction_Check(rec->sibling.ptr())) {
|
|
517
605
|
auto *self = PyCFunction_GET_SELF(rec->sibling.ptr());
|
|
518
|
-
if (
|
|
606
|
+
if (self == nullptr) {
|
|
607
|
+
pybind11_fail(
|
|
608
|
+
"initialize_generic: Unexpected nullptr from PyCFunction_GET_SELF");
|
|
609
|
+
}
|
|
610
|
+
chain = detail::function_record_ptr_from_PyObject(self);
|
|
611
|
+
if (chain && !chain->scope.is(rec->scope)) {
|
|
612
|
+
/* Never append a method to an overload chain of a parent class;
|
|
613
|
+
instead, hide the parent's overloads in this case */
|
|
519
614
|
chain = nullptr;
|
|
520
|
-
} else {
|
|
521
|
-
auto rec_capsule = reinterpret_borrow<capsule>(self);
|
|
522
|
-
if (detail::is_function_record_capsule(rec_capsule)) {
|
|
523
|
-
chain = rec_capsule.get_pointer<detail::function_record>();
|
|
524
|
-
/* Never append a method to an overload chain of a parent class;
|
|
525
|
-
instead, hide the parent's overloads in this case */
|
|
526
|
-
if (!chain->scope.is(rec->scope)) {
|
|
527
|
-
chain = nullptr;
|
|
528
|
-
}
|
|
529
|
-
} else {
|
|
530
|
-
chain = nullptr;
|
|
531
|
-
}
|
|
532
615
|
}
|
|
533
616
|
}
|
|
534
617
|
// Don't trigger for things like the default __init__, which are wrapper_descriptors
|
|
@@ -548,21 +631,13 @@ protected:
|
|
|
548
631
|
= reinterpret_cast<PyCFunction>(reinterpret_cast<void (*)()>(dispatcher));
|
|
549
632
|
rec->def->ml_flags = METH_VARARGS | METH_KEYWORDS;
|
|
550
633
|
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
634
|
+
object py_func_rec = detail::function_record_PyObject_New();
|
|
635
|
+
((detail::function_record_PyObject *) py_func_rec.ptr())->cpp_func_rec
|
|
636
|
+
= unique_rec.release();
|
|
554
637
|
guarded_strdup.release();
|
|
555
638
|
|
|
556
|
-
object scope_module;
|
|
557
|
-
|
|
558
|
-
if (hasattr(rec->scope, "__module__")) {
|
|
559
|
-
scope_module = rec->scope.attr("__module__");
|
|
560
|
-
} else if (hasattr(rec->scope, "__name__")) {
|
|
561
|
-
scope_module = rec->scope.attr("__name__");
|
|
562
|
-
}
|
|
563
|
-
}
|
|
564
|
-
|
|
565
|
-
m_ptr = PyCFunction_NewEx(rec->def, rec_capsule.ptr(), scope_module.ptr());
|
|
639
|
+
object scope_module = detail::get_scope_module(rec->scope);
|
|
640
|
+
m_ptr = PyCFunction_NewEx(rec->def, py_func_rec.ptr(), scope_module.ptr());
|
|
566
641
|
if (!m_ptr) {
|
|
567
642
|
pybind11_fail("cpp_function::cpp_function(): Could not allocate function object");
|
|
568
643
|
}
|
|
@@ -591,9 +666,9 @@ protected:
|
|
|
591
666
|
// chain.
|
|
592
667
|
chain_start = rec;
|
|
593
668
|
rec->next = chain;
|
|
594
|
-
auto
|
|
595
|
-
=
|
|
596
|
-
|
|
669
|
+
auto *py_func_rec
|
|
670
|
+
= (detail::function_record_PyObject *) PyCFunction_GET_SELF(m_ptr);
|
|
671
|
+
py_func_rec->cpp_func_rec = unique_rec.release();
|
|
597
672
|
guarded_strdup.release();
|
|
598
673
|
} else {
|
|
599
674
|
// Or end of chain (normal behavior)
|
|
@@ -610,7 +685,8 @@ protected:
|
|
|
610
685
|
int index = 0;
|
|
611
686
|
/* Create a nice pydoc rec including all signatures and
|
|
612
687
|
docstrings of the functions in the overload chain */
|
|
613
|
-
if (chain && options::show_function_signatures()
|
|
688
|
+
if (chain && options::show_function_signatures()
|
|
689
|
+
&& std::strcmp(rec->name, "_pybind11_conduit_v1_") != 0) {
|
|
614
690
|
// First a generic signature
|
|
615
691
|
signatures += rec->name;
|
|
616
692
|
signatures += "(*args, **kwargs)\n";
|
|
@@ -619,7 +695,8 @@ protected:
|
|
|
619
695
|
// Then specific overload signatures
|
|
620
696
|
bool first_user_def = true;
|
|
621
697
|
for (auto *it = chain_start; it != nullptr; it = it->next) {
|
|
622
|
-
if (options::show_function_signatures()
|
|
698
|
+
if (options::show_function_signatures()
|
|
699
|
+
&& std::strcmp(rec->name, "_pybind11_conduit_v1_") != 0) {
|
|
623
700
|
if (index > 0) {
|
|
624
701
|
signatures += '\n';
|
|
625
702
|
}
|
|
@@ -650,12 +727,11 @@ protected:
|
|
|
650
727
|
}
|
|
651
728
|
}
|
|
652
729
|
|
|
653
|
-
/* Install docstring */
|
|
654
730
|
auto *func = (PyCFunctionObject *) m_ptr;
|
|
655
|
-
std::free(const_cast<char *>(func->m_ml->ml_doc));
|
|
656
731
|
// Install docstring if it's non-empty (when at least one option is enabled)
|
|
657
|
-
|
|
658
|
-
|
|
732
|
+
auto *doc = signatures.empty() ? nullptr : PYBIND11_COMPAT_STRDUP(signatures.c_str());
|
|
733
|
+
std::free(const_cast<char *>(PYBIND11_PYCFUNCTION_GET_DOC(func)));
|
|
734
|
+
PYBIND11_PYCFUNCTION_SET_DOC(func, doc);
|
|
659
735
|
|
|
660
736
|
if (rec->is_method) {
|
|
661
737
|
m_ptr = PYBIND11_INSTANCE_METHOD_NEW(m_ptr, rec->scope.ptr());
|
|
@@ -667,6 +743,8 @@ protected:
|
|
|
667
743
|
}
|
|
668
744
|
}
|
|
669
745
|
|
|
746
|
+
friend void detail::function_record_PyTypeObject_methods::tp_dealloc_impl(PyObject *);
|
|
747
|
+
|
|
670
748
|
/// When a cpp_function is GCed, release any memory allocated by pybind11
|
|
671
749
|
static void destruct(detail::function_record *rec, bool free_strings = true) {
|
|
672
750
|
// If on Python 3.9, check the interpreter "MICRO" (patch) version.
|
|
@@ -716,13 +794,11 @@ protected:
|
|
|
716
794
|
/// Main dispatch logic for calls to functions bound using pybind11
|
|
717
795
|
static PyObject *dispatcher(PyObject *self, PyObject *args_in, PyObject *kwargs_in) {
|
|
718
796
|
using namespace detail;
|
|
719
|
-
|
|
797
|
+
const function_record *overloads = function_record_ptr_from_PyObject(self);
|
|
798
|
+
assert(overloads != nullptr);
|
|
720
799
|
|
|
721
800
|
/* Iterator over the list of potentially admissible overloads */
|
|
722
|
-
const function_record *
|
|
723
|
-
PyCapsule_GetPointer(self, get_function_record_capsule_name())),
|
|
724
|
-
*current_overload = overloads;
|
|
725
|
-
assert(overloads != nullptr);
|
|
801
|
+
const function_record *current_overload = overloads;
|
|
726
802
|
|
|
727
803
|
/* Need to know how many arguments + keyword arguments there are to pick the right
|
|
728
804
|
overload */
|
|
@@ -805,7 +881,7 @@ protected:
|
|
|
805
881
|
function_call call(func, parent);
|
|
806
882
|
|
|
807
883
|
// Protect std::min with parentheses
|
|
808
|
-
size_t args_to_copy = (std::min)(pos_args, n_args_in);
|
|
884
|
+
size_t args_to_copy = (std::min) (pos_args, n_args_in);
|
|
809
885
|
size_t args_copied = 0;
|
|
810
886
|
|
|
811
887
|
// 0. Inject new-style `self` argument
|
|
@@ -1038,33 +1114,7 @@ protected:
|
|
|
1038
1114
|
throw;
|
|
1039
1115
|
#endif
|
|
1040
1116
|
} catch (...) {
|
|
1041
|
-
|
|
1042
|
-
translator a chance to translate it to a Python exception. First
|
|
1043
|
-
all module-local translators will be tried in reverse order of
|
|
1044
|
-
registration. If none of the module-locale translators handle
|
|
1045
|
-
the exception (or there are no module-locale translators) then
|
|
1046
|
-
the global translators will be tried, also in reverse order of
|
|
1047
|
-
registration.
|
|
1048
|
-
|
|
1049
|
-
A translator may choose to do one of the following:
|
|
1050
|
-
|
|
1051
|
-
- catch the exception and call py::set_error()
|
|
1052
|
-
to set a standard (or custom) Python exception, or
|
|
1053
|
-
- do nothing and let the exception fall through to the next translator, or
|
|
1054
|
-
- delegate translation to the next translator by throwing a new type of exception.
|
|
1055
|
-
*/
|
|
1056
|
-
|
|
1057
|
-
auto &local_exception_translators
|
|
1058
|
-
= get_local_internals().registered_exception_translators;
|
|
1059
|
-
if (detail::apply_exception_translators(local_exception_translators)) {
|
|
1060
|
-
return nullptr;
|
|
1061
|
-
}
|
|
1062
|
-
auto &exception_translators = get_internals().registered_exception_translators;
|
|
1063
|
-
if (detail::apply_exception_translators(exception_translators)) {
|
|
1064
|
-
return nullptr;
|
|
1065
|
-
}
|
|
1066
|
-
|
|
1067
|
-
set_error(PyExc_SystemError, "Exception escaped from default exception translator!");
|
|
1117
|
+
try_translate_exceptions();
|
|
1068
1118
|
return nullptr;
|
|
1069
1119
|
}
|
|
1070
1120
|
|
|
@@ -1192,13 +1242,179 @@ protected:
|
|
|
1192
1242
|
|
|
1193
1243
|
PYBIND11_NAMESPACE_BEGIN(detail)
|
|
1194
1244
|
|
|
1245
|
+
PYBIND11_NAMESPACE_BEGIN(function_record_PyTypeObject_methods)
|
|
1246
|
+
|
|
1247
|
+
// This implementation needs the definition of `class cpp_function`.
|
|
1248
|
+
inline void tp_dealloc_impl(PyObject *self) {
|
|
1249
|
+
auto *py_func_rec = (function_record_PyObject *) self;
|
|
1250
|
+
cpp_function::destruct(py_func_rec->cpp_func_rec);
|
|
1251
|
+
py_func_rec->cpp_func_rec = nullptr;
|
|
1252
|
+
}
|
|
1253
|
+
|
|
1254
|
+
PYBIND11_NAMESPACE_END(function_record_PyTypeObject_methods)
|
|
1255
|
+
|
|
1195
1256
|
template <>
|
|
1196
1257
|
struct handle_type_name<cpp_function> {
|
|
1197
|
-
static constexpr auto name = const_name("Callable");
|
|
1258
|
+
static constexpr auto name = const_name("collections.abc.Callable");
|
|
1198
1259
|
};
|
|
1199
1260
|
|
|
1200
1261
|
PYBIND11_NAMESPACE_END(detail)
|
|
1201
1262
|
|
|
1263
|
+
// Use to activate Py_MOD_GIL_NOT_USED.
|
|
1264
|
+
class mod_gil_not_used {
|
|
1265
|
+
public:
|
|
1266
|
+
explicit mod_gil_not_used(bool flag = true) : flag_(flag) {}
|
|
1267
|
+
bool flag() const { return flag_; }
|
|
1268
|
+
|
|
1269
|
+
private:
|
|
1270
|
+
bool flag_;
|
|
1271
|
+
};
|
|
1272
|
+
|
|
1273
|
+
class multiple_interpreters {
|
|
1274
|
+
public:
|
|
1275
|
+
enum class level {
|
|
1276
|
+
not_supported, /// Use to activate Py_MOD_MULTIPLE_INTERPRETERS_NOT_SUPPORTED
|
|
1277
|
+
shared_gil, /// Use to activate Py_MOD_MULTIPLE_INTERPRETERS_SUPPORTED
|
|
1278
|
+
per_interpreter_gil /// Use to activate Py_MOD_PER_INTERPRETER_GIL_SUPPORTED
|
|
1279
|
+
};
|
|
1280
|
+
|
|
1281
|
+
static multiple_interpreters not_supported() {
|
|
1282
|
+
return multiple_interpreters(level::not_supported);
|
|
1283
|
+
}
|
|
1284
|
+
static multiple_interpreters shared_gil() { return multiple_interpreters(level::shared_gil); }
|
|
1285
|
+
static multiple_interpreters per_interpreter_gil() {
|
|
1286
|
+
return multiple_interpreters(level::per_interpreter_gil);
|
|
1287
|
+
}
|
|
1288
|
+
|
|
1289
|
+
explicit constexpr multiple_interpreters(level l) : level_(l) {}
|
|
1290
|
+
level value() const { return level_; }
|
|
1291
|
+
|
|
1292
|
+
private:
|
|
1293
|
+
level level_;
|
|
1294
|
+
};
|
|
1295
|
+
|
|
1296
|
+
PYBIND11_NAMESPACE_BEGIN(detail)
|
|
1297
|
+
|
|
1298
|
+
inline bool gil_not_used_option() { return false; }
|
|
1299
|
+
template <typename F, typename... O>
|
|
1300
|
+
bool gil_not_used_option(F &&, O &&...o);
|
|
1301
|
+
template <typename... O>
|
|
1302
|
+
inline bool gil_not_used_option(mod_gil_not_used f, O &&...o) {
|
|
1303
|
+
return f.flag() || gil_not_used_option(o...);
|
|
1304
|
+
}
|
|
1305
|
+
template <typename F, typename... O>
|
|
1306
|
+
inline bool gil_not_used_option(F &&, O &&...o) {
|
|
1307
|
+
return gil_not_used_option(o...);
|
|
1308
|
+
}
|
|
1309
|
+
|
|
1310
|
+
#ifdef Py_mod_multiple_interpreters
|
|
1311
|
+
inline void *multi_interp_slot() { return Py_MOD_MULTIPLE_INTERPRETERS_NOT_SUPPORTED; }
|
|
1312
|
+
template <typename... O>
|
|
1313
|
+
inline void *multi_interp_slot(multiple_interpreters mi, O &&...o) {
|
|
1314
|
+
switch (mi.value()) {
|
|
1315
|
+
case multiple_interpreters::level::per_interpreter_gil:
|
|
1316
|
+
return Py_MOD_PER_INTERPRETER_GIL_SUPPORTED;
|
|
1317
|
+
case multiple_interpreters::level::shared_gil:
|
|
1318
|
+
return Py_MOD_MULTIPLE_INTERPRETERS_SUPPORTED;
|
|
1319
|
+
case multiple_interpreters::level::not_supported:
|
|
1320
|
+
return Py_MOD_MULTIPLE_INTERPRETERS_NOT_SUPPORTED;
|
|
1321
|
+
}
|
|
1322
|
+
// silence warnings with this unreachable line:
|
|
1323
|
+
return multi_interp_slot(o...);
|
|
1324
|
+
}
|
|
1325
|
+
template <typename F, typename... O>
|
|
1326
|
+
inline void *multi_interp_slot(F &&, O &&...o) {
|
|
1327
|
+
return multi_interp_slot(o...);
|
|
1328
|
+
}
|
|
1329
|
+
#endif
|
|
1330
|
+
|
|
1331
|
+
/*
|
|
1332
|
+
Return a borrowed reference to the named module if it has been successfully initialized within this
|
|
1333
|
+
interpreter before. nullptr if it has not been successfully initialized.
|
|
1334
|
+
*/
|
|
1335
|
+
inline PyObject *get_cached_module(pybind11::str const &nameobj) {
|
|
1336
|
+
dict state = detail::get_python_state_dict();
|
|
1337
|
+
if (!state.contains("__pybind11_module_cache")) {
|
|
1338
|
+
return nullptr;
|
|
1339
|
+
}
|
|
1340
|
+
dict cache = state["__pybind11_module_cache"];
|
|
1341
|
+
if (!cache.contains(nameobj)) {
|
|
1342
|
+
return nullptr;
|
|
1343
|
+
}
|
|
1344
|
+
return cache[nameobj].ptr();
|
|
1345
|
+
}
|
|
1346
|
+
|
|
1347
|
+
/*
|
|
1348
|
+
Add successfully initialized a module object to the internal cache.
|
|
1349
|
+
|
|
1350
|
+
The module must have a __spec__ attribute with a name attribute.
|
|
1351
|
+
*/
|
|
1352
|
+
inline void cache_completed_module(pybind11::object const &mod) {
|
|
1353
|
+
dict state = detail::get_python_state_dict();
|
|
1354
|
+
if (!state.contains("__pybind11_module_cache")) {
|
|
1355
|
+
state["__pybind11_module_cache"] = dict();
|
|
1356
|
+
}
|
|
1357
|
+
state["__pybind11_module_cache"][mod.attr("__spec__").attr("name")] = mod;
|
|
1358
|
+
}
|
|
1359
|
+
|
|
1360
|
+
/*
|
|
1361
|
+
A Py_mod_create slot function which will return the previously created module from the cache if one
|
|
1362
|
+
exists, and otherwise will create a new module object.
|
|
1363
|
+
*/
|
|
1364
|
+
inline PyObject *cached_create_module(PyObject *spec, PyModuleDef *) {
|
|
1365
|
+
(void) &cache_completed_module; // silence unused-function warnings, it is used in a macro
|
|
1366
|
+
|
|
1367
|
+
auto nameobj = getattr(reinterpret_borrow<object>(spec), "name", none());
|
|
1368
|
+
if (nameobj.is_none()) {
|
|
1369
|
+
set_error(PyExc_ImportError, "module spec is missing a name");
|
|
1370
|
+
return nullptr;
|
|
1371
|
+
}
|
|
1372
|
+
|
|
1373
|
+
auto *mod = get_cached_module(nameobj);
|
|
1374
|
+
if (mod) {
|
|
1375
|
+
Py_INCREF(mod);
|
|
1376
|
+
} else {
|
|
1377
|
+
mod = PyModule_NewObject(nameobj.ptr());
|
|
1378
|
+
}
|
|
1379
|
+
return mod;
|
|
1380
|
+
}
|
|
1381
|
+
|
|
1382
|
+
/// Must be a POD type, and must hold enough entries for all of the possible slots PLUS ONE for
|
|
1383
|
+
/// the sentinel (0) end slot.
|
|
1384
|
+
using slots_array = std::array<PyModuleDef_Slot, 5>;
|
|
1385
|
+
|
|
1386
|
+
/// Initialize an array of slots based on the supplied exec slot and options.
|
|
1387
|
+
template <typename... Options>
|
|
1388
|
+
inline slots_array init_slots(int (*exec_fn)(PyObject *), Options &&...options) noexcept {
|
|
1389
|
+
/* NOTE: slots_array MUST be large enough to hold all possible options. If you add an option
|
|
1390
|
+
here, you MUST also increase the size of slots_array in the type alias above! */
|
|
1391
|
+
slots_array mod_def_slots;
|
|
1392
|
+
size_t next_slot = 0;
|
|
1393
|
+
|
|
1394
|
+
mod_def_slots[next_slot++] = {Py_mod_create, reinterpret_cast<void *>(&cached_create_module)};
|
|
1395
|
+
|
|
1396
|
+
if (exec_fn != nullptr) {
|
|
1397
|
+
mod_def_slots[next_slot++] = {Py_mod_exec, reinterpret_cast<void *>(exec_fn)};
|
|
1398
|
+
}
|
|
1399
|
+
|
|
1400
|
+
#ifdef Py_mod_multiple_interpreters
|
|
1401
|
+
mod_def_slots[next_slot++] = {Py_mod_multiple_interpreters, multi_interp_slot(options...)};
|
|
1402
|
+
#endif
|
|
1403
|
+
|
|
1404
|
+
if (gil_not_used_option(options...)) {
|
|
1405
|
+
#if defined(Py_mod_gil) && defined(Py_GIL_DISABLED)
|
|
1406
|
+
mod_def_slots[next_slot++] = {Py_mod_gil, Py_MOD_GIL_NOT_USED};
|
|
1407
|
+
#endif
|
|
1408
|
+
}
|
|
1409
|
+
|
|
1410
|
+
// slots must have a zero end sentinel
|
|
1411
|
+
mod_def_slots[next_slot++] = {0, nullptr};
|
|
1412
|
+
|
|
1413
|
+
return mod_def_slots;
|
|
1414
|
+
}
|
|
1415
|
+
|
|
1416
|
+
PYBIND11_NAMESPACE_END(detail)
|
|
1417
|
+
|
|
1202
1418
|
/// Wrapper for Python extension modules
|
|
1203
1419
|
class module_ : public object {
|
|
1204
1420
|
public:
|
|
@@ -1253,6 +1469,24 @@ public:
|
|
|
1253
1469
|
if (doc && options::show_user_defined_docstrings()) {
|
|
1254
1470
|
result.attr("__doc__") = pybind11::str(doc);
|
|
1255
1471
|
}
|
|
1472
|
+
|
|
1473
|
+
#if defined(GRAALVM_PYTHON) && (!defined(GRAALPY_VERSION_NUM) || GRAALPY_VERSION_NUM < 0x190000)
|
|
1474
|
+
// GraalPy doesn't support PyModule_GetFilenameObject,
|
|
1475
|
+
// so getting by attribute (see PR #5584)
|
|
1476
|
+
handle this_module = m_ptr;
|
|
1477
|
+
if (object this_file = getattr(this_module, "__file__", none())) {
|
|
1478
|
+
result.attr("__file__") = this_file;
|
|
1479
|
+
}
|
|
1480
|
+
#else
|
|
1481
|
+
handle this_file = PyModule_GetFilenameObject(m_ptr);
|
|
1482
|
+
if (this_file) {
|
|
1483
|
+
result.attr("__file__") = this_file;
|
|
1484
|
+
} else if (PyErr_ExceptionMatches(PyExc_SystemError) != 0) {
|
|
1485
|
+
PyErr_Clear();
|
|
1486
|
+
} else {
|
|
1487
|
+
throw error_already_set();
|
|
1488
|
+
}
|
|
1489
|
+
#endif
|
|
1256
1490
|
attr(name) = result;
|
|
1257
1491
|
return result;
|
|
1258
1492
|
}
|
|
@@ -1292,26 +1526,29 @@ public:
|
|
|
1292
1526
|
PyModule_AddObject(ptr(), name, obj.inc_ref().ptr() /* steals a reference */);
|
|
1293
1527
|
}
|
|
1294
1528
|
|
|
1295
|
-
|
|
1529
|
+
// DEPRECATED (since PR #5688): Use PyModuleDef directly instead.
|
|
1530
|
+
using module_def = PyModuleDef;
|
|
1296
1531
|
|
|
1297
1532
|
/** \rst
|
|
1298
1533
|
Create a new top-level module that can be used as the main module of a C extension.
|
|
1299
1534
|
|
|
1300
|
-
``def`` should point to a statically allocated
|
|
1535
|
+
``def`` should point to a statically allocated PyModuleDef.
|
|
1301
1536
|
\endrst */
|
|
1302
|
-
static module_ create_extension_module(const char *name,
|
|
1303
|
-
|
|
1537
|
+
static module_ create_extension_module(const char *name,
|
|
1538
|
+
const char *doc,
|
|
1539
|
+
PyModuleDef *def,
|
|
1540
|
+
mod_gil_not_used gil_not_used
|
|
1541
|
+
= mod_gil_not_used(false)) {
|
|
1304
1542
|
// Placement new (not an allocation).
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
/* m_free */ nullptr};
|
|
1543
|
+
new (def) PyModuleDef{/* m_base */ PyModuleDef_HEAD_INIT,
|
|
1544
|
+
/* m_name */ name,
|
|
1545
|
+
/* m_doc */ options::show_user_defined_docstrings() ? doc : nullptr,
|
|
1546
|
+
/* m_size */ -1,
|
|
1547
|
+
/* m_methods */ nullptr,
|
|
1548
|
+
/* m_slots */ nullptr,
|
|
1549
|
+
/* m_traverse */ nullptr,
|
|
1550
|
+
/* m_clear */ nullptr,
|
|
1551
|
+
/* m_free */ nullptr};
|
|
1315
1552
|
auto *m = PyModule_Create(def);
|
|
1316
1553
|
if (m == nullptr) {
|
|
1317
1554
|
if (PyErr_Occurred()) {
|
|
@@ -1319,6 +1556,11 @@ public:
|
|
|
1319
1556
|
}
|
|
1320
1557
|
pybind11_fail("Internal error in module_::create_extension_module()");
|
|
1321
1558
|
}
|
|
1559
|
+
if (gil_not_used.flag()) {
|
|
1560
|
+
#ifdef Py_GIL_DISABLED
|
|
1561
|
+
PyUnstable_Module_SetGIL(m, Py_MOD_GIL_NOT_USED);
|
|
1562
|
+
#endif
|
|
1563
|
+
}
|
|
1322
1564
|
// TODO: Should be reinterpret_steal for Python 3, but Python also steals it again when
|
|
1323
1565
|
// returned from PyInit_...
|
|
1324
1566
|
// For Python 2, reinterpret_borrow was correct.
|
|
@@ -1330,7 +1572,7 @@ PYBIND11_NAMESPACE_BEGIN(detail)
|
|
|
1330
1572
|
|
|
1331
1573
|
template <>
|
|
1332
1574
|
struct handle_type_name<module_> {
|
|
1333
|
-
static constexpr auto name = const_name("
|
|
1575
|
+
static constexpr auto name = const_name("types.ModuleType");
|
|
1334
1576
|
};
|
|
1335
1577
|
|
|
1336
1578
|
PYBIND11_NAMESPACE_END(detail)
|
|
@@ -1344,15 +1586,14 @@ using module = module_;
|
|
|
1344
1586
|
/// Return a dictionary representing the global variables in the current execution frame,
|
|
1345
1587
|
/// or ``__main__.__dict__`` if there is no frame (usually when the interpreter is embedded).
|
|
1346
1588
|
inline dict globals() {
|
|
1589
|
+
#if PY_VERSION_HEX >= 0x030d0000
|
|
1590
|
+
PyObject *p = PyEval_GetFrameGlobals();
|
|
1591
|
+
return p ? reinterpret_steal<dict>(p)
|
|
1592
|
+
: reinterpret_borrow<dict>(module_::import("__main__").attr("__dict__").ptr());
|
|
1593
|
+
#else
|
|
1347
1594
|
PyObject *p = PyEval_GetGlobals();
|
|
1348
1595
|
return reinterpret_borrow<dict>(p ? p : module_::import("__main__").attr("__dict__").ptr());
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
template <typename... Args, typename = detail::enable_if_t<args_are_all_keyword_or_ds<Args...>()>>
|
|
1352
|
-
PYBIND11_DEPRECATED("make_simple_namespace should be replaced with "
|
|
1353
|
-
"py::module_::import(\"types\").attr(\"SimpleNamespace\") ")
|
|
1354
|
-
object make_simple_namespace(Args &&...args_) {
|
|
1355
|
-
return module_::import("types").attr("SimpleNamespace")(std::forward<Args>(args_)...);
|
|
1596
|
+
#endif
|
|
1356
1597
|
}
|
|
1357
1598
|
|
|
1358
1599
|
PYBIND11_NAMESPACE_BEGIN(detail)
|
|
@@ -1386,20 +1627,32 @@ protected:
|
|
|
1386
1627
|
tinfo->holder_size_in_ptrs = size_in_ptrs(rec.holder_size);
|
|
1387
1628
|
tinfo->init_instance = rec.init_instance;
|
|
1388
1629
|
tinfo->dealloc = rec.dealloc;
|
|
1630
|
+
tinfo->get_trampoline_self_life_support = rec.get_trampoline_self_life_support;
|
|
1389
1631
|
tinfo->simple_type = true;
|
|
1390
1632
|
tinfo->simple_ancestors = true;
|
|
1391
|
-
tinfo->default_holder = rec.default_holder;
|
|
1392
1633
|
tinfo->module_local = rec.module_local;
|
|
1634
|
+
tinfo->holder_enum_v = rec.holder_enum_v;
|
|
1393
1635
|
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
|
|
1399
|
-
|
|
1400
|
-
|
|
1401
|
-
|
|
1402
|
-
|
|
1636
|
+
with_internals([&](internals &internals) {
|
|
1637
|
+
auto tindex = std::type_index(*rec.type);
|
|
1638
|
+
tinfo->direct_conversions = &internals.direct_conversions[tindex];
|
|
1639
|
+
if (rec.module_local) {
|
|
1640
|
+
get_local_internals().registered_types_cpp[tindex] = tinfo;
|
|
1641
|
+
} else {
|
|
1642
|
+
internals.registered_types_cpp[tindex] = tinfo;
|
|
1643
|
+
}
|
|
1644
|
+
|
|
1645
|
+
PYBIND11_WARNING_PUSH
|
|
1646
|
+
#if defined(__GNUC__) && __GNUC__ == 12
|
|
1647
|
+
// When using GCC 12 these warnings are disabled as they trigger
|
|
1648
|
+
// false positive warnings. Discussed here:
|
|
1649
|
+
// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=115824.
|
|
1650
|
+
PYBIND11_WARNING_DISABLE_GCC("-Warray-bounds")
|
|
1651
|
+
PYBIND11_WARNING_DISABLE_GCC("-Wstringop-overread")
|
|
1652
|
+
#endif
|
|
1653
|
+
internals.registered_types_py[(PyTypeObject *) m_ptr] = {tinfo};
|
|
1654
|
+
PYBIND11_WARNING_POP
|
|
1655
|
+
});
|
|
1403
1656
|
|
|
1404
1657
|
if (rec.bases.size() > 1 || rec.multiple_inheritance) {
|
|
1405
1658
|
mark_parents_nonsimple(tinfo->type);
|
|
@@ -1551,6 +1804,239 @@ auto method_adaptor(Return (Class::*pmf)(Args...) const) -> Return (Derived::*)(
|
|
|
1551
1804
|
return pmf;
|
|
1552
1805
|
}
|
|
1553
1806
|
|
|
1807
|
+
PYBIND11_NAMESPACE_BEGIN(detail)
|
|
1808
|
+
|
|
1809
|
+
// Helper for the property_cpp_function static member functions below.
|
|
1810
|
+
// The only purpose of these functions is to support .def_readonly & .def_readwrite.
|
|
1811
|
+
// In this context, the PM template parameter is certain to be a Pointer to a Member.
|
|
1812
|
+
// The main purpose of must_be_member_function_pointer is to make this obvious, and to guard
|
|
1813
|
+
// against accidents. As a side-effect, it also explains why the syntactical overhead for
|
|
1814
|
+
// perfect forwarding is not needed.
|
|
1815
|
+
template <typename PM>
|
|
1816
|
+
using must_be_member_function_pointer = enable_if_t<std::is_member_pointer<PM>::value, int>;
|
|
1817
|
+
|
|
1818
|
+
// Note that property_cpp_function is intentionally in the main pybind11 namespace,
|
|
1819
|
+
// because user-defined specializations could be useful.
|
|
1820
|
+
|
|
1821
|
+
// Classic (non-smart_holder) implementations for .def_readonly and .def_readwrite
|
|
1822
|
+
// getter and setter functions.
|
|
1823
|
+
// WARNING: This classic implementation can lead to dangling pointers for raw pointer members.
|
|
1824
|
+
// See test_ptr() in tests/test_class_sh_property.py
|
|
1825
|
+
// However, this implementation works as-is (and safely) for smart_holder std::shared_ptr members.
|
|
1826
|
+
template <typename T, typename D>
|
|
1827
|
+
struct property_cpp_function_classic {
|
|
1828
|
+
template <typename PM, must_be_member_function_pointer<PM> = 0>
|
|
1829
|
+
static cpp_function readonly(PM pm, const handle &hdl) {
|
|
1830
|
+
return cpp_function([pm](const T &c) -> const D & { return c.*pm; }, is_method(hdl));
|
|
1831
|
+
}
|
|
1832
|
+
|
|
1833
|
+
template <typename PM, must_be_member_function_pointer<PM> = 0>
|
|
1834
|
+
static cpp_function read(PM pm, const handle &hdl) {
|
|
1835
|
+
return readonly(pm, hdl);
|
|
1836
|
+
}
|
|
1837
|
+
|
|
1838
|
+
template <typename PM, must_be_member_function_pointer<PM> = 0>
|
|
1839
|
+
static cpp_function write(PM pm, const handle &hdl) {
|
|
1840
|
+
return cpp_function([pm](T &c, const D &value) { c.*pm = value; }, is_method(hdl));
|
|
1841
|
+
}
|
|
1842
|
+
};
|
|
1843
|
+
|
|
1844
|
+
PYBIND11_NAMESPACE_END(detail)
|
|
1845
|
+
|
|
1846
|
+
template <typename T, typename D, typename SFINAE = void>
|
|
1847
|
+
struct property_cpp_function : detail::property_cpp_function_classic<T, D> {};
|
|
1848
|
+
|
|
1849
|
+
PYBIND11_NAMESPACE_BEGIN(detail)
|
|
1850
|
+
|
|
1851
|
+
template <typename T, typename D, typename SFINAE = void>
|
|
1852
|
+
struct both_t_and_d_use_type_caster_base : std::false_type {};
|
|
1853
|
+
|
|
1854
|
+
// `T` is assumed to be equivalent to `intrinsic_t<T>`.
|
|
1855
|
+
// `D` is may or may not be equivalent to `intrinsic_t<D>`.
|
|
1856
|
+
template <typename T, typename D>
|
|
1857
|
+
struct both_t_and_d_use_type_caster_base<
|
|
1858
|
+
T,
|
|
1859
|
+
D,
|
|
1860
|
+
enable_if_t<all_of<std::is_base_of<type_caster_base<T>, type_caster<T>>,
|
|
1861
|
+
std::is_base_of<type_caster_base<intrinsic_t<D>>, make_caster<D>>>::value>>
|
|
1862
|
+
: std::true_type {};
|
|
1863
|
+
|
|
1864
|
+
// Specialization for raw pointer members, using smart_holder if that is the class_ holder,
|
|
1865
|
+
// or falling back to the classic implementation if not.
|
|
1866
|
+
// WARNING: Like the classic implementation, this implementation can lead to dangling pointers.
|
|
1867
|
+
// See test_ptr() in tests/test_class_sh_property.py
|
|
1868
|
+
// However, the read functions return a shared_ptr to the member, emulating the PyCLIF approach:
|
|
1869
|
+
// https://github.com/google/clif/blob/c371a6d4b28d25d53a16e6d2a6d97305fb1be25a/clif/python/instance.h#L233
|
|
1870
|
+
// This prevents disowning of the Python object owning the raw pointer member.
|
|
1871
|
+
template <typename T, typename D>
|
|
1872
|
+
struct property_cpp_function_sh_raw_ptr_member {
|
|
1873
|
+
using drp = typename std::remove_pointer<D>::type;
|
|
1874
|
+
|
|
1875
|
+
template <typename PM, must_be_member_function_pointer<PM> = 0>
|
|
1876
|
+
static cpp_function readonly(PM pm, const handle &hdl) {
|
|
1877
|
+
type_info *tinfo = get_type_info(typeid(T), /*throw_if_missing=*/true);
|
|
1878
|
+
if (tinfo->holder_enum_v == holder_enum_t::smart_holder) {
|
|
1879
|
+
return cpp_function(
|
|
1880
|
+
[pm](handle c_hdl) -> std::shared_ptr<drp> {
|
|
1881
|
+
std::shared_ptr<T> c_sp
|
|
1882
|
+
= type_caster<std::shared_ptr<T>>::shared_ptr_with_responsible_parent(
|
|
1883
|
+
c_hdl);
|
|
1884
|
+
D ptr = (*c_sp).*pm;
|
|
1885
|
+
return std::shared_ptr<drp>(c_sp, ptr);
|
|
1886
|
+
},
|
|
1887
|
+
is_method(hdl));
|
|
1888
|
+
}
|
|
1889
|
+
return property_cpp_function_classic<T, D>::readonly(pm, hdl);
|
|
1890
|
+
}
|
|
1891
|
+
|
|
1892
|
+
template <typename PM, must_be_member_function_pointer<PM> = 0>
|
|
1893
|
+
static cpp_function read(PM pm, const handle &hdl) {
|
|
1894
|
+
return readonly(pm, hdl);
|
|
1895
|
+
}
|
|
1896
|
+
|
|
1897
|
+
template <typename PM, must_be_member_function_pointer<PM> = 0>
|
|
1898
|
+
static cpp_function write(PM pm, const handle &hdl) {
|
|
1899
|
+
type_info *tinfo = get_type_info(typeid(T), /*throw_if_missing=*/true);
|
|
1900
|
+
if (tinfo->holder_enum_v == holder_enum_t::smart_holder) {
|
|
1901
|
+
return cpp_function([pm](T &c, D value) { c.*pm = std::forward<D>(std::move(value)); },
|
|
1902
|
+
is_method(hdl));
|
|
1903
|
+
}
|
|
1904
|
+
return property_cpp_function_classic<T, D>::write(pm, hdl);
|
|
1905
|
+
}
|
|
1906
|
+
};
|
|
1907
|
+
|
|
1908
|
+
// Specialization for members held by-value, using smart_holder if that is the class_ holder,
|
|
1909
|
+
// or falling back to the classic implementation if not.
|
|
1910
|
+
// The read functions return a shared_ptr to the member, emulating the PyCLIF approach:
|
|
1911
|
+
// https://github.com/google/clif/blob/c371a6d4b28d25d53a16e6d2a6d97305fb1be25a/clif/python/instance.h#L233
|
|
1912
|
+
// This prevents disowning of the Python object owning the member.
|
|
1913
|
+
template <typename T, typename D>
|
|
1914
|
+
struct property_cpp_function_sh_member_held_by_value {
|
|
1915
|
+
template <typename PM, must_be_member_function_pointer<PM> = 0>
|
|
1916
|
+
static cpp_function readonly(PM pm, const handle &hdl) {
|
|
1917
|
+
type_info *tinfo = get_type_info(typeid(T), /*throw_if_missing=*/true);
|
|
1918
|
+
if (tinfo->holder_enum_v == holder_enum_t::smart_holder) {
|
|
1919
|
+
return cpp_function(
|
|
1920
|
+
[pm](handle c_hdl) -> std::shared_ptr<typename std::add_const<D>::type> {
|
|
1921
|
+
std::shared_ptr<T> c_sp
|
|
1922
|
+
= type_caster<std::shared_ptr<T>>::shared_ptr_with_responsible_parent(
|
|
1923
|
+
c_hdl);
|
|
1924
|
+
return std::shared_ptr<typename std::add_const<D>::type>(c_sp,
|
|
1925
|
+
&(c_sp.get()->*pm));
|
|
1926
|
+
},
|
|
1927
|
+
is_method(hdl));
|
|
1928
|
+
}
|
|
1929
|
+
return property_cpp_function_classic<T, D>::readonly(pm, hdl);
|
|
1930
|
+
}
|
|
1931
|
+
|
|
1932
|
+
template <typename PM, must_be_member_function_pointer<PM> = 0>
|
|
1933
|
+
static cpp_function read(PM pm, const handle &hdl) {
|
|
1934
|
+
type_info *tinfo = get_type_info(typeid(T), /*throw_if_missing=*/true);
|
|
1935
|
+
if (tinfo->holder_enum_v == holder_enum_t::smart_holder) {
|
|
1936
|
+
return cpp_function(
|
|
1937
|
+
[pm](handle c_hdl) -> std::shared_ptr<D> {
|
|
1938
|
+
std::shared_ptr<T> c_sp
|
|
1939
|
+
= type_caster<std::shared_ptr<T>>::shared_ptr_with_responsible_parent(
|
|
1940
|
+
c_hdl);
|
|
1941
|
+
return std::shared_ptr<D>(c_sp, &(c_sp.get()->*pm));
|
|
1942
|
+
},
|
|
1943
|
+
is_method(hdl));
|
|
1944
|
+
}
|
|
1945
|
+
return property_cpp_function_classic<T, D>::read(pm, hdl);
|
|
1946
|
+
}
|
|
1947
|
+
|
|
1948
|
+
template <typename PM, must_be_member_function_pointer<PM> = 0>
|
|
1949
|
+
static cpp_function write(PM pm, const handle &hdl) {
|
|
1950
|
+
type_info *tinfo = get_type_info(typeid(T), /*throw_if_missing=*/true);
|
|
1951
|
+
if (tinfo->holder_enum_v == holder_enum_t::smart_holder) {
|
|
1952
|
+
return cpp_function([pm](T &c, const D &value) { c.*pm = value; }, is_method(hdl));
|
|
1953
|
+
}
|
|
1954
|
+
return property_cpp_function_classic<T, D>::write(pm, hdl);
|
|
1955
|
+
}
|
|
1956
|
+
};
|
|
1957
|
+
|
|
1958
|
+
// Specialization for std::unique_ptr members, using smart_holder if that is the class_ holder,
|
|
1959
|
+
// or falling back to the classic implementation if not.
|
|
1960
|
+
// read disowns the member unique_ptr.
|
|
1961
|
+
// write disowns the passed Python object.
|
|
1962
|
+
// readonly is disabled (static_assert) because there is no safe & intuitive way to make the member
|
|
1963
|
+
// accessible as a Python object without disowning the member unique_ptr. A .def_readonly disowning
|
|
1964
|
+
// the unique_ptr member is deemed highly prone to misunderstandings.
|
|
1965
|
+
template <typename T, typename D>
|
|
1966
|
+
struct property_cpp_function_sh_unique_ptr_member {
|
|
1967
|
+
template <typename PM, must_be_member_function_pointer<PM> = 0>
|
|
1968
|
+
static cpp_function readonly(PM, const handle &) {
|
|
1969
|
+
static_assert(!is_instantiation<std::unique_ptr, D>::value,
|
|
1970
|
+
"def_readonly cannot be used for std::unique_ptr members.");
|
|
1971
|
+
return cpp_function{}; // Unreachable.
|
|
1972
|
+
}
|
|
1973
|
+
|
|
1974
|
+
template <typename PM, must_be_member_function_pointer<PM> = 0>
|
|
1975
|
+
static cpp_function read(PM pm, const handle &hdl) {
|
|
1976
|
+
type_info *tinfo = get_type_info(typeid(T), /*throw_if_missing=*/true);
|
|
1977
|
+
if (tinfo->holder_enum_v == holder_enum_t::smart_holder) {
|
|
1978
|
+
return cpp_function(
|
|
1979
|
+
[pm](handle c_hdl) -> D {
|
|
1980
|
+
std::shared_ptr<T> c_sp
|
|
1981
|
+
= type_caster<std::shared_ptr<T>>::shared_ptr_with_responsible_parent(
|
|
1982
|
+
c_hdl);
|
|
1983
|
+
return D{std::move(c_sp.get()->*pm)};
|
|
1984
|
+
},
|
|
1985
|
+
is_method(hdl));
|
|
1986
|
+
}
|
|
1987
|
+
return property_cpp_function_classic<T, D>::read(pm, hdl);
|
|
1988
|
+
}
|
|
1989
|
+
|
|
1990
|
+
template <typename PM, must_be_member_function_pointer<PM> = 0>
|
|
1991
|
+
static cpp_function write(PM pm, const handle &hdl) {
|
|
1992
|
+
return cpp_function([pm](T &c, D &&value) { c.*pm = std::move(value); }, is_method(hdl));
|
|
1993
|
+
}
|
|
1994
|
+
};
|
|
1995
|
+
|
|
1996
|
+
PYBIND11_NAMESPACE_END(detail)
|
|
1997
|
+
|
|
1998
|
+
template <typename T, typename D>
|
|
1999
|
+
struct property_cpp_function<
|
|
2000
|
+
T,
|
|
2001
|
+
D,
|
|
2002
|
+
detail::enable_if_t<detail::all_of<std::is_pointer<D>,
|
|
2003
|
+
detail::both_t_and_d_use_type_caster_base<T, D>>::value>>
|
|
2004
|
+
: detail::property_cpp_function_sh_raw_ptr_member<T, D> {};
|
|
2005
|
+
|
|
2006
|
+
template <typename T, typename D>
|
|
2007
|
+
struct property_cpp_function<T,
|
|
2008
|
+
D,
|
|
2009
|
+
detail::enable_if_t<detail::all_of<
|
|
2010
|
+
detail::none_of<std::is_pointer<D>,
|
|
2011
|
+
std::is_array<D>,
|
|
2012
|
+
detail::is_instantiation<std::unique_ptr, D>,
|
|
2013
|
+
detail::is_instantiation<std::shared_ptr, D>>,
|
|
2014
|
+
detail::both_t_and_d_use_type_caster_base<T, D>>::value>>
|
|
2015
|
+
: detail::property_cpp_function_sh_member_held_by_value<T, D> {};
|
|
2016
|
+
|
|
2017
|
+
template <typename T, typename D>
|
|
2018
|
+
struct property_cpp_function<
|
|
2019
|
+
T,
|
|
2020
|
+
D,
|
|
2021
|
+
detail::enable_if_t<detail::all_of<
|
|
2022
|
+
detail::is_instantiation<std::unique_ptr, D>,
|
|
2023
|
+
detail::both_t_and_d_use_type_caster_base<T, typename D::element_type>>::value>>
|
|
2024
|
+
: detail::property_cpp_function_sh_unique_ptr_member<T, D> {};
|
|
2025
|
+
|
|
2026
|
+
#ifdef PYBIND11_RUN_TESTING_WITH_SMART_HOLDER_AS_DEFAULT_BUT_NEVER_USE_IN_PRODUCTION_PLEASE
|
|
2027
|
+
// NOTE: THIS IS MEANT FOR STRESS-TESTING OR TRIAGING ONLY!
|
|
2028
|
+
// Running the pybind11 unit tests with smart_holder as the default holder is to ensure
|
|
2029
|
+
// that `py::smart_holder` / `py::classh` is backward-compatible with all pre-existing
|
|
2030
|
+
// functionality.
|
|
2031
|
+
// Be careful not to link translation units compiled with different default holders, because
|
|
2032
|
+
// this will cause ODR violations (https://en.wikipedia.org/wiki/One_Definition_Rule).
|
|
2033
|
+
template <typename>
|
|
2034
|
+
using default_holder_type = smart_holder;
|
|
2035
|
+
#else
|
|
2036
|
+
template <typename T>
|
|
2037
|
+
using default_holder_type = std::unique_ptr<T>;
|
|
2038
|
+
#endif
|
|
2039
|
+
|
|
1554
2040
|
template <typename type_, typename... options>
|
|
1555
2041
|
class class_ : public detail::generic_type {
|
|
1556
2042
|
template <typename T>
|
|
@@ -1567,13 +2053,27 @@ public:
|
|
|
1567
2053
|
using type = type_;
|
|
1568
2054
|
using type_alias = detail::exactly_one_t<is_subtype, void, options...>;
|
|
1569
2055
|
constexpr static bool has_alias = !std::is_void<type_alias>::value;
|
|
1570
|
-
using holder_type = detail::exactly_one_t<is_holder,
|
|
2056
|
+
using holder_type = detail::exactly_one_t<is_holder, default_holder_type<type>, options...>;
|
|
1571
2057
|
|
|
1572
2058
|
static_assert(detail::all_of<is_valid_class_option<options>...>::value,
|
|
1573
2059
|
"Unknown/invalid class_ template parameters provided");
|
|
1574
2060
|
|
|
1575
2061
|
static_assert(!has_alias || std::is_polymorphic<type>::value,
|
|
1576
|
-
"Cannot use an alias class with a non-polymorphic type");
|
|
2062
|
+
"Cannot use an alias class (aka trampoline) with a non-polymorphic type");
|
|
2063
|
+
|
|
2064
|
+
#ifndef PYBIND11_RUN_TESTING_WITH_SMART_HOLDER_AS_DEFAULT_BUT_NEVER_USE_IN_PRODUCTION_PLEASE
|
|
2065
|
+
static_assert(!has_alias || !detail::is_smart_holder<holder_type>::value
|
|
2066
|
+
|| std::is_base_of<trampoline_self_life_support, type_alias>::value,
|
|
2067
|
+
"Alias class (aka trampoline) must inherit from"
|
|
2068
|
+
" pybind11::trampoline_self_life_support if used in combination with"
|
|
2069
|
+
" pybind11::smart_holder");
|
|
2070
|
+
#endif
|
|
2071
|
+
static_assert(!has_alias || detail::is_smart_holder<holder_type>::value
|
|
2072
|
+
|| !std::is_base_of<trampoline_self_life_support, type_alias>::value,
|
|
2073
|
+
"pybind11::trampoline_self_life_support is a smart_holder feature, therefore"
|
|
2074
|
+
" an alias class (aka trampoline) should inherit from"
|
|
2075
|
+
" pybind11::trampoline_self_life_support only if used in combination with"
|
|
2076
|
+
" pybind11::smart_holder");
|
|
1577
2077
|
|
|
1578
2078
|
PYBIND11_OBJECT(class_, generic_type, PyType_Check)
|
|
1579
2079
|
|
|
@@ -1598,8 +2098,16 @@ public:
|
|
|
1598
2098
|
record.type_align = alignof(conditional_t<has_alias, type_alias, type> &);
|
|
1599
2099
|
record.holder_size = sizeof(holder_type);
|
|
1600
2100
|
record.init_instance = init_instance;
|
|
1601
|
-
|
|
1602
|
-
|
|
2101
|
+
|
|
2102
|
+
if (detail::is_instantiation<std::unique_ptr, holder_type>::value) {
|
|
2103
|
+
record.holder_enum_v = detail::holder_enum_t::std_unique_ptr;
|
|
2104
|
+
} else if (detail::is_instantiation<std::shared_ptr, holder_type>::value) {
|
|
2105
|
+
record.holder_enum_v = detail::holder_enum_t::std_shared_ptr;
|
|
2106
|
+
} else if (std::is_same<holder_type, smart_holder>::value) {
|
|
2107
|
+
record.holder_enum_v = detail::holder_enum_t::smart_holder;
|
|
2108
|
+
} else {
|
|
2109
|
+
record.holder_enum_v = detail::holder_enum_t::custom_holder;
|
|
2110
|
+
}
|
|
1603
2111
|
|
|
1604
2112
|
set_operator_new<type>(&record);
|
|
1605
2113
|
|
|
@@ -1609,14 +2117,33 @@ public:
|
|
|
1609
2117
|
/* Process optional arguments, if any */
|
|
1610
2118
|
process_attributes<Extra...>::init(extra..., &record);
|
|
1611
2119
|
|
|
2120
|
+
if (record.release_gil_before_calling_cpp_dtor) {
|
|
2121
|
+
record.dealloc = dealloc_release_gil_before_calling_cpp_dtor;
|
|
2122
|
+
} else {
|
|
2123
|
+
record.dealloc = dealloc_without_manipulating_gil;
|
|
2124
|
+
}
|
|
2125
|
+
|
|
2126
|
+
if (std::is_base_of<trampoline_self_life_support, type_alias>::value) {
|
|
2127
|
+
// Store a cross-DSO-safe getter.
|
|
2128
|
+
// This lambda is defined in the same DSO that instantiates
|
|
2129
|
+
// class_<type, alias_type>, but it can be called safely from any other DSO.
|
|
2130
|
+
record.get_trampoline_self_life_support = [](void *type_ptr) {
|
|
2131
|
+
return dynamic_raw_ptr_cast_if_possible<trampoline_self_life_support>(
|
|
2132
|
+
static_cast<type *>(type_ptr));
|
|
2133
|
+
};
|
|
2134
|
+
}
|
|
2135
|
+
|
|
1612
2136
|
generic_type::initialize(record);
|
|
1613
2137
|
|
|
1614
2138
|
if (has_alias) {
|
|
1615
|
-
|
|
1616
|
-
|
|
1617
|
-
|
|
1618
|
-
|
|
2139
|
+
with_internals([&](internals &internals) {
|
|
2140
|
+
auto &instances = record.module_local ? get_local_internals().registered_types_cpp
|
|
2141
|
+
: internals.registered_types_cpp;
|
|
2142
|
+
instances[std::type_index(typeid(type_alias))]
|
|
2143
|
+
= instances[std::type_index(typeid(type))];
|
|
2144
|
+
});
|
|
1619
2145
|
}
|
|
2146
|
+
def("_pybind11_conduit_v1_", cpp_conduit_method);
|
|
1620
2147
|
}
|
|
1621
2148
|
|
|
1622
2149
|
template <typename Base, detail::enable_if_t<is_base<Base>::value, int> = 0>
|
|
@@ -1729,9 +2256,11 @@ public:
|
|
|
1729
2256
|
class_ &def_readwrite(const char *name, D C::*pm, const Extra &...extra) {
|
|
1730
2257
|
static_assert(std::is_same<C, type>::value || std::is_base_of<C, type>::value,
|
|
1731
2258
|
"def_readwrite() requires a class member (or base class member)");
|
|
1732
|
-
|
|
1733
|
-
|
|
1734
|
-
|
|
2259
|
+
def_property(name,
|
|
2260
|
+
property_cpp_function<type, D>::read(pm, *this),
|
|
2261
|
+
property_cpp_function<type, D>::write(pm, *this),
|
|
2262
|
+
return_value_policy::reference_internal,
|
|
2263
|
+
extra...);
|
|
1735
2264
|
return *this;
|
|
1736
2265
|
}
|
|
1737
2266
|
|
|
@@ -1739,8 +2268,10 @@ public:
|
|
|
1739
2268
|
class_ &def_readonly(const char *name, const D C::*pm, const Extra &...extra) {
|
|
1740
2269
|
static_assert(std::is_same<C, type>::value || std::is_base_of<C, type>::value,
|
|
1741
2270
|
"def_readonly() requires a class member (or base class member)");
|
|
1742
|
-
|
|
1743
|
-
|
|
2271
|
+
def_property_readonly(name,
|
|
2272
|
+
property_cpp_function<type, D>::readonly(pm, *this),
|
|
2273
|
+
return_value_policy::reference_internal,
|
|
2274
|
+
extra...);
|
|
1744
2275
|
return *this;
|
|
1745
2276
|
}
|
|
1746
2277
|
|
|
@@ -1917,6 +2448,8 @@ private:
|
|
|
1917
2448
|
/// instance. Should be called as soon as the `type` value_ptr is set for an instance. Takes
|
|
1918
2449
|
/// an optional pointer to an existing holder to use; if not specified and the instance is
|
|
1919
2450
|
/// `.owned`, a new holder will be constructed to manage the value pointer.
|
|
2451
|
+
template <typename H = holder_type,
|
|
2452
|
+
detail::enable_if_t<!detail::is_smart_holder<H>::value, int> = 0>
|
|
1920
2453
|
static void init_instance(detail::instance *inst, const void *holder_ptr) {
|
|
1921
2454
|
auto v_h = inst->get_value_and_holder(detail::get_type_info(typeid(type)));
|
|
1922
2455
|
if (!v_h.instance_registered()) {
|
|
@@ -1926,15 +2459,73 @@ private:
|
|
|
1926
2459
|
init_holder(inst, v_h, (const holder_type *) holder_ptr, v_h.value_ptr<type>());
|
|
1927
2460
|
}
|
|
1928
2461
|
|
|
1929
|
-
|
|
1930
|
-
static
|
|
1931
|
-
|
|
1932
|
-
|
|
1933
|
-
|
|
1934
|
-
|
|
1935
|
-
|
|
1936
|
-
|
|
1937
|
-
|
|
2462
|
+
template <typename WrappedType>
|
|
2463
|
+
static bool try_initialization_using_shared_from_this(holder_type *, WrappedType *, ...) {
|
|
2464
|
+
return false;
|
|
2465
|
+
}
|
|
2466
|
+
|
|
2467
|
+
// Adopting existing approach used by type_caster_base, although it leads to somewhat fuzzy
|
|
2468
|
+
// ownership semantics: if we detected via shared_from_this that a shared_ptr exists already,
|
|
2469
|
+
// it is reused, irrespective of the return_value_policy in effect.
|
|
2470
|
+
// "SomeBaseOfWrappedType" is needed because std::enable_shared_from_this is not necessarily a
|
|
2471
|
+
// direct base of WrappedType.
|
|
2472
|
+
template <typename WrappedType, typename SomeBaseOfWrappedType>
|
|
2473
|
+
static bool try_initialization_using_shared_from_this(
|
|
2474
|
+
holder_type *uninitialized_location,
|
|
2475
|
+
WrappedType *value_ptr_w_t,
|
|
2476
|
+
const std::enable_shared_from_this<SomeBaseOfWrappedType> *) {
|
|
2477
|
+
auto shd_ptr = std::dynamic_pointer_cast<WrappedType>(
|
|
2478
|
+
detail::try_get_shared_from_this(value_ptr_w_t));
|
|
2479
|
+
if (!shd_ptr) {
|
|
2480
|
+
return false;
|
|
2481
|
+
}
|
|
2482
|
+
// Note: inst->owned ignored.
|
|
2483
|
+
new (uninitialized_location) holder_type(holder_type::from_shared_ptr(shd_ptr));
|
|
2484
|
+
return true;
|
|
2485
|
+
}
|
|
2486
|
+
|
|
2487
|
+
template <typename H = holder_type,
|
|
2488
|
+
detail::enable_if_t<detail::is_smart_holder<H>::value, int> = 0>
|
|
2489
|
+
static void init_instance(detail::instance *inst, const void *holder_const_void_ptr) {
|
|
2490
|
+
// Need for const_cast is a consequence of the type_info::init_instance type:
|
|
2491
|
+
// void (*init_instance)(instance *, const void *);
|
|
2492
|
+
auto *holder_void_ptr = const_cast<void *>(holder_const_void_ptr);
|
|
2493
|
+
|
|
2494
|
+
auto v_h = inst->get_value_and_holder(detail::get_type_info(typeid(type)));
|
|
2495
|
+
if (!v_h.instance_registered()) {
|
|
2496
|
+
register_instance(inst, v_h.value_ptr(), v_h.type);
|
|
2497
|
+
v_h.set_instance_registered();
|
|
2498
|
+
}
|
|
2499
|
+
auto *uninitialized_location = std::addressof(v_h.holder<holder_type>());
|
|
2500
|
+
auto *value_ptr_w_t = v_h.value_ptr<type>();
|
|
2501
|
+
// Try downcast from `type` to `type_alias`:
|
|
2502
|
+
inst->is_alias
|
|
2503
|
+
= detail::dynamic_raw_ptr_cast_if_possible<type_alias>(value_ptr_w_t) != nullptr;
|
|
2504
|
+
if (holder_void_ptr) {
|
|
2505
|
+
// Note: inst->owned ignored.
|
|
2506
|
+
auto *holder_ptr = static_cast<holder_type *>(holder_void_ptr);
|
|
2507
|
+
new (uninitialized_location) holder_type(std::move(*holder_ptr));
|
|
2508
|
+
} else if (!try_initialization_using_shared_from_this(
|
|
2509
|
+
uninitialized_location, value_ptr_w_t, value_ptr_w_t)) {
|
|
2510
|
+
if (inst->owned) {
|
|
2511
|
+
new (uninitialized_location) holder_type(holder_type::from_raw_ptr_take_ownership(
|
|
2512
|
+
value_ptr_w_t, /*void_cast_raw_ptr*/ inst->is_alias));
|
|
2513
|
+
} else {
|
|
2514
|
+
new (uninitialized_location)
|
|
2515
|
+
holder_type(holder_type::from_raw_ptr_unowned(value_ptr_w_t));
|
|
2516
|
+
}
|
|
2517
|
+
}
|
|
2518
|
+
v_h.set_holder_constructed();
|
|
2519
|
+
}
|
|
2520
|
+
|
|
2521
|
+
// Deallocates an instance; via holder, if constructed; otherwise via operator delete.
|
|
2522
|
+
// NOTE: The Python error indicator needs to cleared BEFORE this function is called.
|
|
2523
|
+
// This is because we could be deallocating while cleaning up after a Python exception.
|
|
2524
|
+
// If the error indicator is not cleared but the C++ destructor code makes Python C API
|
|
2525
|
+
// calls, those calls are likely to generate a new exception, and pybind11 will then
|
|
2526
|
+
// throw `error_already_set` from the C++ destructor. This is forbidden and will
|
|
2527
|
+
// trigger std::terminate().
|
|
2528
|
+
static void dealloc_impl(detail::value_and_holder &v_h) {
|
|
1938
2529
|
if (v_h.holder_constructed()) {
|
|
1939
2530
|
v_h.holder<holder_type>().~holder_type();
|
|
1940
2531
|
v_h.set_holder_constructed(false);
|
|
@@ -1945,6 +2536,32 @@ private:
|
|
|
1945
2536
|
v_h.value_ptr() = nullptr;
|
|
1946
2537
|
}
|
|
1947
2538
|
|
|
2539
|
+
static void dealloc_without_manipulating_gil(detail::value_and_holder &v_h) {
|
|
2540
|
+
error_scope scope;
|
|
2541
|
+
dealloc_impl(v_h);
|
|
2542
|
+
}
|
|
2543
|
+
|
|
2544
|
+
static void dealloc_release_gil_before_calling_cpp_dtor(detail::value_and_holder &v_h) {
|
|
2545
|
+
error_scope scope;
|
|
2546
|
+
// Intentionally not using `gil_scoped_release` because the non-simple
|
|
2547
|
+
// version unconditionally calls `get_internals()`.
|
|
2548
|
+
// `Py_BEGIN_ALLOW_THREADS`, `Py_END_ALLOW_THREADS` cannot be used
|
|
2549
|
+
// because those macros include `{` and `}`.
|
|
2550
|
+
PyThreadState *py_ts = PyEval_SaveThread();
|
|
2551
|
+
try {
|
|
2552
|
+
dealloc_impl(v_h);
|
|
2553
|
+
} catch (...) {
|
|
2554
|
+
// This code path is expected to be unreachable unless there is a
|
|
2555
|
+
// bug in pybind11 itself.
|
|
2556
|
+
// An alternative would be to mark this function, or
|
|
2557
|
+
// `dealloc_impl()`, with `nothrow`, but that would be a subtle
|
|
2558
|
+
// behavior change and could make debugging more difficult.
|
|
2559
|
+
PyEval_RestoreThread(py_ts);
|
|
2560
|
+
throw;
|
|
2561
|
+
}
|
|
2562
|
+
PyEval_RestoreThread(py_ts);
|
|
2563
|
+
}
|
|
2564
|
+
|
|
1948
2565
|
static detail::function_record *get_function_record(handle h) {
|
|
1949
2566
|
h = detail::get_function(h);
|
|
1950
2567
|
if (!h) {
|
|
@@ -1955,17 +2572,15 @@ private:
|
|
|
1955
2572
|
if (!func_self) {
|
|
1956
2573
|
throw error_already_set();
|
|
1957
2574
|
}
|
|
1958
|
-
|
|
1959
|
-
return nullptr;
|
|
1960
|
-
}
|
|
1961
|
-
auto cap = reinterpret_borrow<capsule>(func_self);
|
|
1962
|
-
if (!detail::is_function_record_capsule(cap)) {
|
|
1963
|
-
return nullptr;
|
|
1964
|
-
}
|
|
1965
|
-
return cap.get_pointer<detail::function_record>();
|
|
2575
|
+
return detail::function_record_ptr_from_PyObject(func_self.ptr());
|
|
1966
2576
|
}
|
|
1967
2577
|
};
|
|
1968
2578
|
|
|
2579
|
+
// Supports easier switching between py::class_<T> and py::class_<T, py::smart_holder>:
|
|
2580
|
+
// users can simply replace the `_` in `class_` with `h` or vice versa.
|
|
2581
|
+
template <typename type_, typename... options>
|
|
2582
|
+
using classh = class_<type_, smart_holder, options...>;
|
|
2583
|
+
|
|
1969
2584
|
/// Binds an existing constructor taking arguments Args...
|
|
1970
2585
|
template <typename... Args>
|
|
1971
2586
|
detail::initimpl::constructor<Args...> init() {
|
|
@@ -2002,7 +2617,7 @@ detail::initimpl::pickle_factory<GetState, SetState> pickle(GetState &&g, SetSta
|
|
|
2002
2617
|
PYBIND11_NAMESPACE_BEGIN(detail)
|
|
2003
2618
|
|
|
2004
2619
|
inline str enum_name(handle arg) {
|
|
2005
|
-
dict entries = arg
|
|
2620
|
+
dict entries = type::handle_of(arg).attr("__entries");
|
|
2006
2621
|
for (auto kv : entries) {
|
|
2007
2622
|
if (handle(kv.second[int_(0)]).equal(arg)) {
|
|
2008
2623
|
return pybind11::str(kv.first);
|
|
@@ -2027,9 +2642,11 @@ struct enum_base {
|
|
|
2027
2642
|
.format(std::move(type_name), enum_name(arg), int_(arg));
|
|
2028
2643
|
},
|
|
2029
2644
|
name("__repr__"),
|
|
2030
|
-
is_method(m_base)
|
|
2645
|
+
is_method(m_base),
|
|
2646
|
+
pos_only());
|
|
2031
2647
|
|
|
2032
|
-
m_base.attr("name")
|
|
2648
|
+
m_base.attr("name")
|
|
2649
|
+
= property(cpp_function(&enum_name, name("name"), is_method(m_base), pos_only()));
|
|
2033
2650
|
|
|
2034
2651
|
m_base.attr("__str__") = cpp_function(
|
|
2035
2652
|
[](handle arg) -> str {
|
|
@@ -2037,7 +2654,8 @@ struct enum_base {
|
|
|
2037
2654
|
return pybind11::str("{}.{}").format(std::move(type_name), enum_name(arg));
|
|
2038
2655
|
},
|
|
2039
2656
|
name("__str__"),
|
|
2040
|
-
is_method(m_base)
|
|
2657
|
+
is_method(m_base),
|
|
2658
|
+
pos_only());
|
|
2041
2659
|
|
|
2042
2660
|
if (options::show_enum_members_docstring()) {
|
|
2043
2661
|
m_base.attr("__doc__") = static_property(
|
|
@@ -2092,7 +2710,8 @@ struct enum_base {
|
|
|
2092
2710
|
}, \
|
|
2093
2711
|
name(op), \
|
|
2094
2712
|
is_method(m_base), \
|
|
2095
|
-
arg("other")
|
|
2713
|
+
arg("other"), \
|
|
2714
|
+
pos_only())
|
|
2096
2715
|
|
|
2097
2716
|
#define PYBIND11_ENUM_OP_CONV(op, expr) \
|
|
2098
2717
|
m_base.attr(op) = cpp_function( \
|
|
@@ -2102,7 +2721,8 @@ struct enum_base {
|
|
|
2102
2721
|
}, \
|
|
2103
2722
|
name(op), \
|
|
2104
2723
|
is_method(m_base), \
|
|
2105
|
-
arg("other")
|
|
2724
|
+
arg("other"), \
|
|
2725
|
+
pos_only())
|
|
2106
2726
|
|
|
2107
2727
|
#define PYBIND11_ENUM_OP_CONV_LHS(op, expr) \
|
|
2108
2728
|
m_base.attr(op) = cpp_function( \
|
|
@@ -2112,7 +2732,8 @@ struct enum_base {
|
|
|
2112
2732
|
}, \
|
|
2113
2733
|
name(op), \
|
|
2114
2734
|
is_method(m_base), \
|
|
2115
|
-
arg("other")
|
|
2735
|
+
arg("other"), \
|
|
2736
|
+
pos_only())
|
|
2116
2737
|
|
|
2117
2738
|
if (is_convertible) {
|
|
2118
2739
|
PYBIND11_ENUM_OP_CONV_LHS("__eq__", !b.is_none() && a.equal(b));
|
|
@@ -2132,7 +2753,8 @@ struct enum_base {
|
|
|
2132
2753
|
m_base.attr("__invert__")
|
|
2133
2754
|
= cpp_function([](const object &arg) { return ~(int_(arg)); },
|
|
2134
2755
|
name("__invert__"),
|
|
2135
|
-
is_method(m_base)
|
|
2756
|
+
is_method(m_base),
|
|
2757
|
+
pos_only());
|
|
2136
2758
|
}
|
|
2137
2759
|
} else {
|
|
2138
2760
|
PYBIND11_ENUM_OP_STRICT("__eq__", int_(a).equal(int_(b)), return false);
|
|
@@ -2152,11 +2774,15 @@ struct enum_base {
|
|
|
2152
2774
|
#undef PYBIND11_ENUM_OP_CONV
|
|
2153
2775
|
#undef PYBIND11_ENUM_OP_STRICT
|
|
2154
2776
|
|
|
2155
|
-
m_base.attr("__getstate__") = cpp_function(
|
|
2156
|
-
|
|
2777
|
+
m_base.attr("__getstate__") = cpp_function([](const object &arg) { return int_(arg); },
|
|
2778
|
+
name("__getstate__"),
|
|
2779
|
+
is_method(m_base),
|
|
2780
|
+
pos_only());
|
|
2157
2781
|
|
|
2158
|
-
m_base.attr("__hash__") = cpp_function(
|
|
2159
|
-
|
|
2782
|
+
m_base.attr("__hash__") = cpp_function([](const object &arg) { return int_(arg); },
|
|
2783
|
+
name("__hash__"),
|
|
2784
|
+
is_method(m_base),
|
|
2785
|
+
pos_only());
|
|
2160
2786
|
}
|
|
2161
2787
|
|
|
2162
2788
|
PYBIND11_NOINLINE void value(char const *name_, object value, const char *doc = nullptr) {
|
|
@@ -2243,14 +2869,22 @@ public:
|
|
|
2243
2869
|
template <typename... Extra>
|
|
2244
2870
|
enum_(const handle &scope, const char *name, const Extra &...extra)
|
|
2245
2871
|
: class_<Type>(scope, name, extra...), m_base(*this, scope) {
|
|
2872
|
+
{
|
|
2873
|
+
if (detail::global_internals_native_enum_type_map_contains(
|
|
2874
|
+
std::type_index(typeid(Type)))) {
|
|
2875
|
+
pybind11_fail("pybind11::enum_ \"" + std::string(name)
|
|
2876
|
+
+ "\" is already registered as a pybind11::native_enum!");
|
|
2877
|
+
}
|
|
2878
|
+
}
|
|
2879
|
+
|
|
2246
2880
|
constexpr bool is_arithmetic = detail::any_of<std::is_same<arithmetic, Extra>...>::value;
|
|
2247
2881
|
constexpr bool is_convertible = std::is_convertible<Type, Underlying>::value;
|
|
2248
2882
|
m_base.init(is_arithmetic, is_convertible);
|
|
2249
2883
|
|
|
2250
2884
|
def(init([](Scalar i) { return static_cast<Type>(i); }), arg("value"));
|
|
2251
|
-
def_property_readonly("value", [](Type value) { return (Scalar) value; });
|
|
2252
|
-
def("__int__", [](Type value) { return (Scalar) value; });
|
|
2253
|
-
def("__index__", [](Type value) { return (Scalar) value; });
|
|
2885
|
+
def_property_readonly("value", [](Type value) { return (Scalar) value; }, pos_only());
|
|
2886
|
+
def("__int__", [](Type value) { return (Scalar) value; }, pos_only());
|
|
2887
|
+
def("__index__", [](Type value) { return (Scalar) value; }, pos_only());
|
|
2254
2888
|
attr("__setstate__") = cpp_function(
|
|
2255
2889
|
[](detail::value_and_holder &v_h, Scalar arg) {
|
|
2256
2890
|
detail::initimpl::setstate<Base>(
|
|
@@ -2259,7 +2893,8 @@ public:
|
|
|
2259
2893
|
detail::is_new_style_constructor(),
|
|
2260
2894
|
pybind11::name("__setstate__"),
|
|
2261
2895
|
is_method(*this),
|
|
2262
|
-
arg("state")
|
|
2896
|
+
arg("state"),
|
|
2897
|
+
pos_only());
|
|
2263
2898
|
}
|
|
2264
2899
|
|
|
2265
2900
|
/// Export enumeration entries into the parent scope
|
|
@@ -2330,28 +2965,39 @@ keep_alive_impl(size_t Nurse, size_t Patient, function_call &call, handle ret) {
|
|
|
2330
2965
|
|
|
2331
2966
|
inline std::pair<decltype(internals::registered_types_py)::iterator, bool>
|
|
2332
2967
|
all_type_info_get_cache(PyTypeObject *type) {
|
|
2333
|
-
auto res =
|
|
2334
|
-
|
|
2968
|
+
auto res = with_internals([type](internals &internals) {
|
|
2969
|
+
auto ins = internals
|
|
2970
|
+
.registered_types_py
|
|
2335
2971
|
#ifdef __cpp_lib_unordered_map_try_emplace
|
|
2336
|
-
|
|
2972
|
+
.try_emplace(type);
|
|
2337
2973
|
#else
|
|
2338
|
-
|
|
2974
|
+
.emplace(type, std::vector<detail::type_info *>());
|
|
2339
2975
|
#endif
|
|
2976
|
+
if (ins.second) {
|
|
2977
|
+
// For free-threading mode, this call must be under
|
|
2978
|
+
// the with_internals() mutex lock, to avoid that other threads
|
|
2979
|
+
// continue running with the empty ins.first->second.
|
|
2980
|
+
all_type_info_populate(type, ins.first->second);
|
|
2981
|
+
}
|
|
2982
|
+
return ins;
|
|
2983
|
+
});
|
|
2340
2984
|
if (res.second) {
|
|
2341
2985
|
// New cache entry created; set up a weak reference to automatically remove it if the type
|
|
2342
2986
|
// gets destroyed:
|
|
2343
2987
|
weakref((PyObject *) type, cpp_function([type](handle wr) {
|
|
2344
|
-
|
|
2345
|
-
|
|
2346
|
-
|
|
2347
|
-
|
|
2348
|
-
|
|
2349
|
-
|
|
2350
|
-
it
|
|
2351
|
-
|
|
2352
|
-
|
|
2988
|
+
with_internals([type](internals &internals) {
|
|
2989
|
+
internals.registered_types_py.erase(type);
|
|
2990
|
+
|
|
2991
|
+
// TODO consolidate the erasure code in pybind11_meta_dealloc() in class.h
|
|
2992
|
+
auto &cache = internals.inactive_override_cache;
|
|
2993
|
+
for (auto it = cache.begin(), last = cache.end(); it != last;) {
|
|
2994
|
+
if (it->first == reinterpret_cast<PyObject *>(type)) {
|
|
2995
|
+
it = cache.erase(it);
|
|
2996
|
+
} else {
|
|
2997
|
+
++it;
|
|
2998
|
+
}
|
|
2353
2999
|
}
|
|
2354
|
-
}
|
|
3000
|
+
});
|
|
2355
3001
|
|
|
2356
3002
|
wr.dec_ref();
|
|
2357
3003
|
}))
|
|
@@ -2428,13 +3074,15 @@ template <typename Access,
|
|
|
2428
3074
|
typename Sentinel,
|
|
2429
3075
|
typename ValueType,
|
|
2430
3076
|
typename... Extra>
|
|
3077
|
+
// NOLINTNEXTLINE(performance-unnecessary-value-param)
|
|
2431
3078
|
iterator make_iterator_impl(Iterator first, Sentinel last, Extra &&...extra) {
|
|
2432
3079
|
using state = detail::iterator_state<Access, Policy, Iterator, Sentinel, ValueType, Extra...>;
|
|
2433
3080
|
// TODO: state captures only the types of Extra, not the values
|
|
2434
3081
|
|
|
2435
3082
|
if (!detail::get_type_info(typeid(state), false)) {
|
|
2436
3083
|
class_<state>(handle(), "iterator", pybind11::module_local())
|
|
2437
|
-
.def(
|
|
3084
|
+
.def(
|
|
3085
|
+
"__iter__", [](state &s) -> state & { return s; }, pos_only())
|
|
2438
3086
|
.def(
|
|
2439
3087
|
"__next__",
|
|
2440
3088
|
[](state &s) -> ValueType {
|
|
@@ -2451,6 +3099,7 @@ iterator make_iterator_impl(Iterator first, Sentinel last, Extra &&...extra) {
|
|
|
2451
3099
|
// NOLINTNEXTLINE(readability-const-return-type) // PR #3263
|
|
2452
3100
|
},
|
|
2453
3101
|
std::forward<Extra>(extra)...,
|
|
3102
|
+
pos_only(),
|
|
2454
3103
|
Policy);
|
|
2455
3104
|
}
|
|
2456
3105
|
|
|
@@ -2465,6 +3114,7 @@ template <return_value_policy Policy = return_value_policy::reference_internal,
|
|
|
2465
3114
|
typename Sentinel,
|
|
2466
3115
|
typename ValueType = typename detail::iterator_access<Iterator>::result_type,
|
|
2467
3116
|
typename... Extra>
|
|
3117
|
+
// NOLINTNEXTLINE(performance-unnecessary-value-param)
|
|
2468
3118
|
typing::Iterator<ValueType> make_iterator(Iterator first, Sentinel last, Extra &&...extra) {
|
|
2469
3119
|
return detail::make_iterator_impl<detail::iterator_access<Iterator>,
|
|
2470
3120
|
Policy,
|
|
@@ -2550,13 +3200,22 @@ typing::Iterator<ValueType> make_value_iterator(Type &value, Extra &&...extra) {
|
|
|
2550
3200
|
|
|
2551
3201
|
template <typename InputType, typename OutputType>
|
|
2552
3202
|
void implicitly_convertible() {
|
|
3203
|
+
static int tss_sentinel_pointee = 1; // arbitrary value
|
|
2553
3204
|
struct set_flag {
|
|
2554
|
-
|
|
2555
|
-
explicit set_flag(
|
|
2556
|
-
|
|
3205
|
+
thread_specific_storage<int> &flag;
|
|
3206
|
+
explicit set_flag(thread_specific_storage<int> &flag_) : flag(flag_) {
|
|
3207
|
+
flag = &tss_sentinel_pointee; // trick: the pointer itself is the sentinel
|
|
3208
|
+
}
|
|
3209
|
+
~set_flag() { flag.reset(nullptr); }
|
|
3210
|
+
|
|
3211
|
+
// Prevent copying/moving to ensure RAII guard is used safely
|
|
3212
|
+
set_flag(const set_flag &) = delete;
|
|
3213
|
+
set_flag(set_flag &&) = delete;
|
|
3214
|
+
set_flag &operator=(const set_flag &) = delete;
|
|
3215
|
+
set_flag &operator=(set_flag &&) = delete;
|
|
2557
3216
|
};
|
|
2558
3217
|
auto implicit_caster = [](PyObject *obj, PyTypeObject *type) -> PyObject * {
|
|
2559
|
-
static
|
|
3218
|
+
static thread_specific_storage<int> currently_used;
|
|
2560
3219
|
if (currently_used) { // implicit conversions are non-reentrant
|
|
2561
3220
|
return nullptr;
|
|
2562
3221
|
}
|
|
@@ -2581,8 +3240,12 @@ void implicitly_convertible() {
|
|
|
2581
3240
|
}
|
|
2582
3241
|
|
|
2583
3242
|
inline void register_exception_translator(ExceptionTranslator &&translator) {
|
|
2584
|
-
detail::
|
|
2585
|
-
std::
|
|
3243
|
+
detail::with_exception_translators(
|
|
3244
|
+
[&](std::forward_list<ExceptionTranslator> &exception_translators,
|
|
3245
|
+
std::forward_list<ExceptionTranslator> &local_exception_translators) {
|
|
3246
|
+
(void) local_exception_translators;
|
|
3247
|
+
exception_translators.push_front(std::forward<ExceptionTranslator>(translator));
|
|
3248
|
+
});
|
|
2586
3249
|
}
|
|
2587
3250
|
|
|
2588
3251
|
/**
|
|
@@ -2592,8 +3255,12 @@ inline void register_exception_translator(ExceptionTranslator &&translator) {
|
|
|
2592
3255
|
* the exception.
|
|
2593
3256
|
*/
|
|
2594
3257
|
inline void register_local_exception_translator(ExceptionTranslator &&translator) {
|
|
2595
|
-
detail::
|
|
2596
|
-
std::
|
|
3258
|
+
detail::with_exception_translators(
|
|
3259
|
+
[&](std::forward_list<ExceptionTranslator> &exception_translators,
|
|
3260
|
+
std::forward_list<ExceptionTranslator> &local_exception_translators) {
|
|
3261
|
+
(void) exception_translators;
|
|
3262
|
+
local_exception_translators.push_front(std::forward<ExceptionTranslator>(translator));
|
|
3263
|
+
});
|
|
2597
3264
|
}
|
|
2598
3265
|
|
|
2599
3266
|
/**
|
|
@@ -2750,27 +3417,37 @@ get_type_override(const void *this_ptr, const type_info *this_type, const char *
|
|
|
2750
3417
|
|
|
2751
3418
|
/* Cache functions that aren't overridden in Python to avoid
|
|
2752
3419
|
many costly Python dictionary lookups below */
|
|
2753
|
-
|
|
2754
|
-
|
|
3420
|
+
bool not_overridden = with_internals([&key](internals &internals) {
|
|
3421
|
+
auto &cache = internals.inactive_override_cache;
|
|
3422
|
+
return cache.find(key) != cache.end();
|
|
3423
|
+
});
|
|
3424
|
+
if (not_overridden) {
|
|
2755
3425
|
return function();
|
|
2756
3426
|
}
|
|
2757
3427
|
|
|
2758
3428
|
function override = getattr(self, name, function());
|
|
2759
3429
|
if (override.is_cpp_function()) {
|
|
2760
|
-
|
|
3430
|
+
with_internals([&](internals &internals) {
|
|
3431
|
+
internals.inactive_override_cache.insert(std::move(key));
|
|
3432
|
+
});
|
|
2761
3433
|
return function();
|
|
2762
3434
|
}
|
|
2763
3435
|
|
|
2764
3436
|
/* Don't call dispatch code if invoked from overridden function.
|
|
2765
|
-
Unfortunately this doesn't work on PyPy. */
|
|
2766
|
-
#if !defined(PYPY_VERSION)
|
|
3437
|
+
Unfortunately this doesn't work on PyPy and GraalPy. */
|
|
3438
|
+
#if !defined(PYPY_VERSION) && !defined(GRAALVM_PYTHON)
|
|
2767
3439
|
# if PY_VERSION_HEX >= 0x03090000
|
|
2768
3440
|
PyFrameObject *frame = PyThreadState_GetFrame(PyThreadState_Get());
|
|
2769
3441
|
if (frame != nullptr) {
|
|
2770
3442
|
PyCodeObject *f_code = PyFrame_GetCode(frame);
|
|
2771
3443
|
// f_code is guaranteed to not be NULL
|
|
2772
3444
|
if ((std::string) str(f_code->co_name) == name && f_code->co_argcount > 0) {
|
|
3445
|
+
# if PY_VERSION_HEX >= 0x030d0000
|
|
3446
|
+
PyObject *locals = PyEval_GetFrameLocals();
|
|
3447
|
+
# else
|
|
2773
3448
|
PyObject *locals = PyEval_GetLocals();
|
|
3449
|
+
Py_XINCREF(locals);
|
|
3450
|
+
# endif
|
|
2774
3451
|
if (locals != nullptr) {
|
|
2775
3452
|
# if PY_VERSION_HEX >= 0x030b0000
|
|
2776
3453
|
PyObject *co_varnames = PyCode_GetVarnames(f_code);
|
|
@@ -2780,6 +3457,7 @@ get_type_override(const void *this_ptr, const type_info *this_type, const char *
|
|
|
2780
3457
|
PyObject *self_arg = PyTuple_GET_ITEM(co_varnames, 0);
|
|
2781
3458
|
Py_DECREF(co_varnames);
|
|
2782
3459
|
PyObject *self_caller = dict_getitem(locals, self_arg);
|
|
3460
|
+
Py_DECREF(locals);
|
|
2783
3461
|
if (self_caller == self.ptr()) {
|
|
2784
3462
|
Py_DECREF(f_code);
|
|
2785
3463
|
Py_DECREF(frame);
|
|
@@ -2856,10 +3534,14 @@ function get_override(const T *this_ptr, const char *name) {
|
|
|
2856
3534
|
= pybind11::get_override(static_cast<const cname *>(this), name); \
|
|
2857
3535
|
if (override) { \
|
|
2858
3536
|
auto o = override(__VA_ARGS__); \
|
|
2859
|
-
|
|
3537
|
+
PYBIND11_WARNING_PUSH \
|
|
3538
|
+
PYBIND11_WARNING_DISABLE_MSVC(4127) \
|
|
3539
|
+
if (pybind11::detail::cast_is_temporary_value_reference<ret_type>::value \
|
|
3540
|
+
&& !pybind11::detail::is_same_ignoring_cvref<ret_type, PyObject *>::value) { \
|
|
2860
3541
|
static pybind11::detail::override_caster_t<ret_type> caster; \
|
|
2861
3542
|
return pybind11::detail::cast_ref<ret_type>(std::move(o), caster); \
|
|
2862
3543
|
} \
|
|
3544
|
+
PYBIND11_WARNING_POP \
|
|
2863
3545
|
return pybind11::detail::cast_safe<ret_type>(std::move(o)); \
|
|
2864
3546
|
} \
|
|
2865
3547
|
} while (false)
|