netgen-mesher 6.2.2506.post35.dev0__cp314-cp314-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/NgOCC.py +7 -0
- netgen/__init__.py +114 -0
- netgen/__init__.pyi +22 -0
- netgen/__main__.py +53 -0
- netgen/cmake/NetgenConfig.cmake +79 -0
- netgen/cmake/netgen-targets-release.cmake +69 -0
- netgen/cmake/netgen-targets.cmake +146 -0
- netgen/config/__init__.py +1 -0
- netgen/config/__init__.pyi +52 -0
- netgen/config/__main__.py +4 -0
- netgen/config/config.py +68 -0
- netgen/config/config.pyi +54 -0
- netgen/csg.py +25 -0
- netgen/geom2d.py +178 -0
- netgen/gui.py +82 -0
- netgen/include/core/archive.hpp +1256 -0
- netgen/include/core/array.hpp +1760 -0
- netgen/include/core/autodiff.hpp +1131 -0
- netgen/include/core/autodiffdiff.hpp +733 -0
- netgen/include/core/bitarray.hpp +240 -0
- netgen/include/core/concurrentqueue.h +3619 -0
- netgen/include/core/exception.hpp +145 -0
- netgen/include/core/flags.hpp +199 -0
- netgen/include/core/hashtable.hpp +1281 -0
- netgen/include/core/localheap.hpp +318 -0
- netgen/include/core/logging.hpp +117 -0
- netgen/include/core/memtracer.hpp +221 -0
- netgen/include/core/mpi4py_pycapi.h +245 -0
- netgen/include/core/mpi_wrapper.hpp +643 -0
- netgen/include/core/ng_mpi.hpp +94 -0
- netgen/include/core/ng_mpi_generated_declarations.hpp +155 -0
- netgen/include/core/ng_mpi_native.hpp +25 -0
- netgen/include/core/ngcore.hpp +32 -0
- netgen/include/core/ngcore_api.hpp +152 -0
- netgen/include/core/ngstream.hpp +115 -0
- netgen/include/core/paje_trace.hpp +279 -0
- netgen/include/core/profiler.hpp +382 -0
- netgen/include/core/python_ngcore.hpp +457 -0
- netgen/include/core/ranges.hpp +109 -0
- netgen/include/core/register_archive.hpp +100 -0
- netgen/include/core/signal.hpp +82 -0
- netgen/include/core/simd.hpp +160 -0
- netgen/include/core/simd_arm64.hpp +407 -0
- netgen/include/core/simd_avx.hpp +394 -0
- netgen/include/core/simd_avx512.hpp +285 -0
- netgen/include/core/simd_generic.hpp +1053 -0
- netgen/include/core/simd_math.hpp +178 -0
- netgen/include/core/simd_sse.hpp +289 -0
- netgen/include/core/statushandler.hpp +37 -0
- netgen/include/core/symboltable.hpp +153 -0
- netgen/include/core/table.hpp +810 -0
- netgen/include/core/taskmanager.hpp +1161 -0
- netgen/include/core/type_traits.hpp +65 -0
- netgen/include/core/utils.hpp +385 -0
- netgen/include/core/version.hpp +102 -0
- netgen/include/core/xbool.hpp +47 -0
- netgen/include/csg/algprim.hpp +563 -0
- netgen/include/csg/brick.hpp +150 -0
- netgen/include/csg/csg.hpp +43 -0
- netgen/include/csg/csgeom.hpp +389 -0
- netgen/include/csg/csgparser.hpp +101 -0
- netgen/include/csg/curve2d.hpp +67 -0
- netgen/include/csg/edgeflw.hpp +112 -0
- netgen/include/csg/explicitcurve2d.hpp +113 -0
- netgen/include/csg/extrusion.hpp +185 -0
- netgen/include/csg/gencyl.hpp +70 -0
- netgen/include/csg/geoml.hpp +16 -0
- netgen/include/csg/identify.hpp +213 -0
- netgen/include/csg/manifold.hpp +29 -0
- netgen/include/csg/meshsurf.hpp +46 -0
- netgen/include/csg/polyhedra.hpp +121 -0
- netgen/include/csg/revolution.hpp +180 -0
- netgen/include/csg/singularref.hpp +84 -0
- netgen/include/csg/solid.hpp +295 -0
- netgen/include/csg/specpoin.hpp +194 -0
- netgen/include/csg/spline3d.hpp +99 -0
- netgen/include/csg/splinesurface.hpp +85 -0
- netgen/include/csg/surface.hpp +394 -0
- netgen/include/csg/triapprox.hpp +63 -0
- netgen/include/csg/vscsg.hpp +34 -0
- netgen/include/general/autodiff.hpp +356 -0
- netgen/include/general/autoptr.hpp +39 -0
- netgen/include/general/gzstream.h +121 -0
- netgen/include/general/hashtabl.hpp +1692 -0
- netgen/include/general/myadt.hpp +48 -0
- netgen/include/general/mystring.hpp +226 -0
- netgen/include/general/netgenout.hpp +205 -0
- netgen/include/general/ngarray.hpp +797 -0
- netgen/include/general/ngbitarray.hpp +149 -0
- netgen/include/general/ngpython.hpp +74 -0
- netgen/include/general/optmem.hpp +44 -0
- netgen/include/general/parthreads.hpp +138 -0
- netgen/include/general/seti.hpp +50 -0
- netgen/include/general/sort.hpp +47 -0
- netgen/include/general/spbita2d.hpp +59 -0
- netgen/include/general/stack.hpp +114 -0
- netgen/include/general/table.hpp +280 -0
- netgen/include/general/template.hpp +509 -0
- netgen/include/geom2d/csg2d.hpp +750 -0
- netgen/include/geom2d/geometry2d.hpp +280 -0
- netgen/include/geom2d/spline2d.hpp +234 -0
- netgen/include/geom2d/vsgeom2d.hpp +28 -0
- netgen/include/gprim/adtree.hpp +1392 -0
- netgen/include/gprim/geom2d.hpp +858 -0
- netgen/include/gprim/geom3d.hpp +749 -0
- netgen/include/gprim/geomfuncs.hpp +212 -0
- netgen/include/gprim/geomobjects.hpp +544 -0
- netgen/include/gprim/geomops.hpp +404 -0
- netgen/include/gprim/geomtest3d.hpp +101 -0
- netgen/include/gprim/gprim.hpp +33 -0
- netgen/include/gprim/spline.hpp +778 -0
- netgen/include/gprim/splinegeometry.hpp +73 -0
- netgen/include/gprim/transform3d.hpp +216 -0
- netgen/include/include/acisgeom.hpp +3 -0
- netgen/include/include/csg.hpp +1 -0
- netgen/include/include/geometry2d.hpp +1 -0
- netgen/include/include/gprim.hpp +1 -0
- netgen/include/include/incopengl.hpp +62 -0
- netgen/include/include/inctcl.hpp +13 -0
- netgen/include/include/incvis.hpp +6 -0
- netgen/include/include/linalg.hpp +1 -0
- netgen/include/include/meshing.hpp +1 -0
- netgen/include/include/myadt.hpp +1 -0
- netgen/include/include/mydefs.hpp +70 -0
- netgen/include/include/mystdlib.h +59 -0
- netgen/include/include/netgen_config.hpp +27 -0
- netgen/include/include/netgen_version.hpp +9 -0
- netgen/include/include/nginterface_v2_impl.hpp +395 -0
- netgen/include/include/ngsimd.hpp +1 -0
- netgen/include/include/occgeom.hpp +1 -0
- netgen/include/include/opti.hpp +1 -0
- netgen/include/include/parallel.hpp +1 -0
- netgen/include/include/stlgeom.hpp +1 -0
- netgen/include/include/visual.hpp +1 -0
- netgen/include/interface/rw_medit.hpp +11 -0
- netgen/include/interface/writeuser.hpp +80 -0
- netgen/include/linalg/densemat.hpp +414 -0
- netgen/include/linalg/linalg.hpp +29 -0
- netgen/include/linalg/opti.hpp +142 -0
- netgen/include/linalg/polynomial.hpp +47 -0
- netgen/include/linalg/vector.hpp +217 -0
- netgen/include/meshing/adfront2.hpp +274 -0
- netgen/include/meshing/adfront3.hpp +332 -0
- netgen/include/meshing/basegeom.hpp +370 -0
- netgen/include/meshing/bcfunctions.hpp +53 -0
- netgen/include/meshing/bisect.hpp +72 -0
- netgen/include/meshing/boundarylayer.hpp +113 -0
- netgen/include/meshing/classifyhpel.hpp +1984 -0
- netgen/include/meshing/clusters.hpp +46 -0
- netgen/include/meshing/curvedelems.hpp +274 -0
- netgen/include/meshing/delaunay2d.hpp +73 -0
- netgen/include/meshing/fieldlines.hpp +103 -0
- netgen/include/meshing/findip.hpp +198 -0
- netgen/include/meshing/findip2.hpp +103 -0
- netgen/include/meshing/geomsearch.hpp +69 -0
- netgen/include/meshing/global.hpp +54 -0
- netgen/include/meshing/hpref_hex.hpp +330 -0
- netgen/include/meshing/hpref_prism.hpp +3405 -0
- netgen/include/meshing/hpref_pyramid.hpp +154 -0
- netgen/include/meshing/hpref_quad.hpp +2082 -0
- netgen/include/meshing/hpref_segm.hpp +122 -0
- netgen/include/meshing/hpref_tet.hpp +4230 -0
- netgen/include/meshing/hpref_trig.hpp +848 -0
- netgen/include/meshing/hprefinement.hpp +366 -0
- netgen/include/meshing/improve2.hpp +178 -0
- netgen/include/meshing/improve3.hpp +151 -0
- netgen/include/meshing/localh.hpp +223 -0
- netgen/include/meshing/meshclass.hpp +1076 -0
- netgen/include/meshing/meshfunc.hpp +47 -0
- netgen/include/meshing/meshing.hpp +63 -0
- netgen/include/meshing/meshing2.hpp +163 -0
- netgen/include/meshing/meshing3.hpp +123 -0
- netgen/include/meshing/meshtool.hpp +90 -0
- netgen/include/meshing/meshtype.hpp +1930 -0
- netgen/include/meshing/msghandler.hpp +62 -0
- netgen/include/meshing/paralleltop.hpp +172 -0
- netgen/include/meshing/python_mesh.hpp +206 -0
- netgen/include/meshing/ruler2.hpp +172 -0
- netgen/include/meshing/ruler3.hpp +211 -0
- netgen/include/meshing/soldata.hpp +141 -0
- netgen/include/meshing/specials.hpp +17 -0
- netgen/include/meshing/surfacegeom.hpp +73 -0
- netgen/include/meshing/topology.hpp +1003 -0
- netgen/include/meshing/validate.hpp +21 -0
- netgen/include/meshing/visual_interface.hpp +71 -0
- netgen/include/mydefs.hpp +70 -0
- netgen/include/nginterface.h +474 -0
- netgen/include/nginterface_v2.hpp +406 -0
- netgen/include/nglib.h +697 -0
- netgen/include/nglib_occ.h +50 -0
- netgen/include/occ/occ_edge.hpp +47 -0
- netgen/include/occ/occ_face.hpp +52 -0
- netgen/include/occ/occ_solid.hpp +23 -0
- netgen/include/occ/occ_utils.hpp +376 -0
- netgen/include/occ/occ_vertex.hpp +30 -0
- netgen/include/occ/occgeom.hpp +659 -0
- netgen/include/occ/occmeshsurf.hpp +168 -0
- netgen/include/occ/vsocc.hpp +33 -0
- netgen/include/pybind11/LICENSE +29 -0
- netgen/include/pybind11/attr.h +722 -0
- netgen/include/pybind11/buffer_info.h +208 -0
- netgen/include/pybind11/cast.h +2361 -0
- netgen/include/pybind11/chrono.h +228 -0
- netgen/include/pybind11/common.h +2 -0
- netgen/include/pybind11/complex.h +74 -0
- 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 +823 -0
- netgen/include/pybind11/detail/common.h +1348 -0
- netgen/include/pybind11/detail/cpp_conduit.h +75 -0
- netgen/include/pybind11/detail/descr.h +226 -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 +538 -0
- netgen/include/pybind11/detail/internals.h +799 -0
- 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 +1591 -0
- netgen/include/pybind11/detail/typeid.h +65 -0
- netgen/include/pybind11/detail/using_smart_holder.h +22 -0
- netgen/include/pybind11/detail/value_and_holder.h +90 -0
- netgen/include/pybind11/eigen/common.h +9 -0
- netgen/include/pybind11/eigen/matrix.h +723 -0
- netgen/include/pybind11/eigen/tensor.h +521 -0
- netgen/include/pybind11/eigen.h +12 -0
- netgen/include/pybind11/embed.h +320 -0
- netgen/include/pybind11/eval.h +161 -0
- netgen/include/pybind11/functional.h +147 -0
- netgen/include/pybind11/gil.h +199 -0
- netgen/include/pybind11/gil_safe_call_once.h +102 -0
- netgen/include/pybind11/gil_simple.h +37 -0
- netgen/include/pybind11/iostream.h +265 -0
- netgen/include/pybind11/native_enum.h +67 -0
- netgen/include/pybind11/numpy.h +2312 -0
- netgen/include/pybind11/operators.h +202 -0
- netgen/include/pybind11/options.h +92 -0
- netgen/include/pybind11/pybind11.h +3645 -0
- netgen/include/pybind11/pytypes.h +2680 -0
- netgen/include/pybind11/stl/filesystem.h +114 -0
- netgen/include/pybind11/stl.h +666 -0
- netgen/include/pybind11/stl_bind.h +858 -0
- netgen/include/pybind11/subinterpreter.h +299 -0
- netgen/include/pybind11/trampoline_self_life_support.h +65 -0
- netgen/include/pybind11/type_caster_pyobject_ptr.h +61 -0
- netgen/include/pybind11/typing.h +298 -0
- netgen/include/pybind11/warnings.h +75 -0
- netgen/include/stlgeom/meshstlsurface.hpp +67 -0
- netgen/include/stlgeom/stlgeom.hpp +491 -0
- netgen/include/stlgeom/stlline.hpp +193 -0
- netgen/include/stlgeom/stltool.hpp +331 -0
- netgen/include/stlgeom/stltopology.hpp +419 -0
- netgen/include/stlgeom/vsstl.hpp +58 -0
- netgen/include/visualization/meshdoc.hpp +42 -0
- netgen/include/visualization/mvdraw.hpp +325 -0
- netgen/include/visualization/vispar.hpp +128 -0
- netgen/include/visualization/visual.hpp +28 -0
- netgen/include/visualization/visual_api.hpp +10 -0
- netgen/include/visualization/vssolution.hpp +399 -0
- netgen/lib/libnggui.lib +0 -0
- netgen/lib/ngcore.lib +0 -0
- netgen/lib/nglib.lib +0 -0
- netgen/lib/togl.lib +0 -0
- netgen/libnggui.dll +0 -0
- netgen/libngguipy.lib +0 -0
- netgen/libngguipy.pyd +0 -0
- netgen/libngpy/_NgOCC.pyi +1545 -0
- netgen/libngpy/__init__.pyi +7 -0
- netgen/libngpy/_csg.pyi +259 -0
- netgen/libngpy/_geom2d.pyi +323 -0
- netgen/libngpy/_meshing.pyi +1111 -0
- netgen/libngpy/_stl.pyi +131 -0
- netgen/libngpy.lib +0 -0
- netgen/libngpy.pyd +0 -0
- netgen/meshing.py +65 -0
- netgen/ngcore.dll +0 -0
- netgen/nglib.dll +0 -0
- netgen/occ.py +52 -0
- netgen/read_gmsh.py +259 -0
- netgen/read_meshio.py +22 -0
- netgen/stl.py +2 -0
- netgen/togl.dll +0 -0
- netgen/version.py +2 -0
- netgen/webgui.py +529 -0
- netgen_mesher-6.2.2506.post35.dev0.data/data/share/netgen/boundarycondition.geo +16 -0
- netgen_mesher-6.2.2506.post35.dev0.data/data/share/netgen/boxcyl.geo +32 -0
- netgen_mesher-6.2.2506.post35.dev0.data/data/share/netgen/circle_on_cube.geo +27 -0
- netgen_mesher-6.2.2506.post35.dev0.data/data/share/netgen/cone.geo +13 -0
- netgen_mesher-6.2.2506.post35.dev0.data/data/share/netgen/cube.geo +16 -0
- netgen_mesher-6.2.2506.post35.dev0.data/data/share/netgen/cubeandring.geo +55 -0
- netgen_mesher-6.2.2506.post35.dev0.data/data/share/netgen/cubeandspheres.geo +21 -0
- netgen_mesher-6.2.2506.post35.dev0.data/data/share/netgen/cubemcyl.geo +18 -0
- netgen_mesher-6.2.2506.post35.dev0.data/data/share/netgen/cubemsphere.geo +19 -0
- netgen_mesher-6.2.2506.post35.dev0.data/data/share/netgen/cylinder.geo +12 -0
- netgen_mesher-6.2.2506.post35.dev0.data/data/share/netgen/cylsphere.geo +12 -0
- netgen_mesher-6.2.2506.post35.dev0.data/data/share/netgen/doc/ng4.pdf +0 -0
- netgen_mesher-6.2.2506.post35.dev0.data/data/share/netgen/ellipsoid.geo +8 -0
- netgen_mesher-6.2.2506.post35.dev0.data/data/share/netgen/ellipticcyl.geo +10 -0
- netgen_mesher-6.2.2506.post35.dev0.data/data/share/netgen/extrusion.geo +99 -0
- netgen_mesher-6.2.2506.post35.dev0.data/data/share/netgen/fichera.geo +24 -0
- netgen_mesher-6.2.2506.post35.dev0.data/data/share/netgen/frame.step +11683 -0
- netgen_mesher-6.2.2506.post35.dev0.data/data/share/netgen/hinge.stl +8486 -0
- netgen_mesher-6.2.2506.post35.dev0.data/data/share/netgen/lshape3d.geo +26 -0
- netgen_mesher-6.2.2506.post35.dev0.data/data/share/netgen/manyholes.geo +26 -0
- netgen_mesher-6.2.2506.post35.dev0.data/data/share/netgen/manyholes2.geo +26 -0
- netgen_mesher-6.2.2506.post35.dev0.data/data/share/netgen/matrix.geo +27 -0
- netgen_mesher-6.2.2506.post35.dev0.data/data/share/netgen/ortho.geo +11 -0
- netgen_mesher-6.2.2506.post35.dev0.data/data/share/netgen/part1.stl +2662 -0
- netgen_mesher-6.2.2506.post35.dev0.data/data/share/netgen/period.geo +33 -0
- netgen_mesher-6.2.2506.post35.dev0.data/data/share/netgen/py_tutorials/exportNeutral.py +26 -0
- netgen_mesher-6.2.2506.post35.dev0.data/data/share/netgen/py_tutorials/mesh.py +19 -0
- netgen_mesher-6.2.2506.post35.dev0.data/data/share/netgen/py_tutorials/shaft.geo +65 -0
- netgen_mesher-6.2.2506.post35.dev0.data/data/share/netgen/revolution.geo +18 -0
- netgen_mesher-6.2.2506.post35.dev0.data/data/share/netgen/screw.step +1694 -0
- netgen_mesher-6.2.2506.post35.dev0.data/data/share/netgen/sculpture.geo +13 -0
- netgen_mesher-6.2.2506.post35.dev0.data/data/share/netgen/shaft.geo +65 -0
- netgen_mesher-6.2.2506.post35.dev0.data/data/share/netgen/shell.geo +10 -0
- netgen_mesher-6.2.2506.post35.dev0.data/data/share/netgen/sphere.geo +8 -0
- netgen_mesher-6.2.2506.post35.dev0.data/data/share/netgen/sphereincube.geo +17 -0
- netgen_mesher-6.2.2506.post35.dev0.data/data/share/netgen/square.in2d +35 -0
- netgen_mesher-6.2.2506.post35.dev0.data/data/share/netgen/squarecircle.in2d +48 -0
- netgen_mesher-6.2.2506.post35.dev0.data/data/share/netgen/squarehole.in2d +47 -0
- netgen_mesher-6.2.2506.post35.dev0.data/data/share/netgen/torus.geo +8 -0
- netgen_mesher-6.2.2506.post35.dev0.data/data/share/netgen/trafo.geo +57 -0
- netgen_mesher-6.2.2506.post35.dev0.data/data/share/netgen/twobricks.geo +15 -0
- netgen_mesher-6.2.2506.post35.dev0.data/data/share/netgen/twocubes.geo +18 -0
- netgen_mesher-6.2.2506.post35.dev0.data/data/share/netgen/twocyl.geo +16 -0
- netgen_mesher-6.2.2506.post35.dev0.dist-info/METADATA +15 -0
- netgen_mesher-6.2.2506.post35.dev0.dist-info/RECORD +340 -0
- netgen_mesher-6.2.2506.post35.dev0.dist-info/WHEEL +5 -0
- netgen_mesher-6.2.2506.post35.dev0.dist-info/entry_points.txt +2 -0
- netgen_mesher-6.2.2506.post35.dev0.dist-info/licenses/AUTHORS +1 -0
- netgen_mesher-6.2.2506.post35.dev0.dist-info/licenses/LICENSE +504 -0
- netgen_mesher-6.2.2506.post35.dev0.dist-info/top_level.txt +2 -0
- pyngcore/__init__.py +1 -0
- pyngcore/pyngcore.cp314-win_amd64.pyd +0 -0
|
@@ -0,0 +1,1591 @@
|
|
|
1
|
+
/*
|
|
2
|
+
pybind11/detail/type_caster_base.h (originally first part of pybind11/cast.h)
|
|
3
|
+
|
|
4
|
+
Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch>
|
|
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/gil.h>
|
|
13
|
+
#include <pybind11/pytypes.h>
|
|
14
|
+
#include <pybind11/trampoline_self_life_support.h>
|
|
15
|
+
|
|
16
|
+
#include "common.h"
|
|
17
|
+
#include "cpp_conduit.h"
|
|
18
|
+
#include "descr.h"
|
|
19
|
+
#include "dynamic_raw_ptr_cast_if_possible.h"
|
|
20
|
+
#include "internals.h"
|
|
21
|
+
#include "typeid.h"
|
|
22
|
+
#include "using_smart_holder.h"
|
|
23
|
+
#include "value_and_holder.h"
|
|
24
|
+
|
|
25
|
+
#include <cstdint>
|
|
26
|
+
#include <cstring>
|
|
27
|
+
#include <iterator>
|
|
28
|
+
#include <new>
|
|
29
|
+
#include <stdexcept>
|
|
30
|
+
#include <string>
|
|
31
|
+
#include <type_traits>
|
|
32
|
+
#include <typeindex>
|
|
33
|
+
#include <typeinfo>
|
|
34
|
+
#include <unordered_map>
|
|
35
|
+
#include <utility>
|
|
36
|
+
#include <vector>
|
|
37
|
+
|
|
38
|
+
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
|
|
39
|
+
PYBIND11_NAMESPACE_BEGIN(detail)
|
|
40
|
+
|
|
41
|
+
/// A life support system for temporary objects created by `type_caster::load()`.
|
|
42
|
+
/// Adding a patient will keep it alive up until the enclosing function returns.
|
|
43
|
+
class loader_life_support {
|
|
44
|
+
private:
|
|
45
|
+
loader_life_support *parent = nullptr;
|
|
46
|
+
std::unordered_set<PyObject *> keep_alive;
|
|
47
|
+
|
|
48
|
+
public:
|
|
49
|
+
/// A new patient frame is created when a function is entered
|
|
50
|
+
loader_life_support() {
|
|
51
|
+
auto &stack_top = get_internals().loader_life_support_tls;
|
|
52
|
+
parent = stack_top.get();
|
|
53
|
+
stack_top = this;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/// ... and destroyed after it returns
|
|
57
|
+
~loader_life_support() {
|
|
58
|
+
auto &stack_top = get_internals().loader_life_support_tls;
|
|
59
|
+
if (stack_top.get() != this) {
|
|
60
|
+
pybind11_fail("loader_life_support: internal error");
|
|
61
|
+
}
|
|
62
|
+
stack_top = parent;
|
|
63
|
+
for (auto *item : keep_alive) {
|
|
64
|
+
Py_DECREF(item);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/// This can only be used inside a pybind11-bound function, either by `argument_loader`
|
|
69
|
+
/// at argument preparation time or by `py::cast()` at execution time.
|
|
70
|
+
PYBIND11_NOINLINE static void add_patient(handle h) {
|
|
71
|
+
loader_life_support *frame = get_internals().loader_life_support_tls.get();
|
|
72
|
+
if (!frame) {
|
|
73
|
+
// NOTE: It would be nice to include the stack frames here, as this indicates
|
|
74
|
+
// use of pybind11::cast<> outside the normal call framework, finding such
|
|
75
|
+
// a location is challenging. Developers could consider printing out
|
|
76
|
+
// stack frame addresses here using something like __builtin_frame_address(0)
|
|
77
|
+
throw cast_error("When called outside a bound function, py::cast() cannot "
|
|
78
|
+
"do Python -> C++ conversions which require the creation "
|
|
79
|
+
"of temporary values");
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
if (frame->keep_alive.insert(h.ptr()).second) {
|
|
83
|
+
Py_INCREF(h.ptr());
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
// Gets the cache entry for the given type, creating it if necessary. The return value is the pair
|
|
89
|
+
// returned by emplace, i.e. an iterator for the entry and a bool set to `true` if the entry was
|
|
90
|
+
// just created.
|
|
91
|
+
inline std::pair<decltype(internals::registered_types_py)::iterator, bool>
|
|
92
|
+
all_type_info_get_cache(PyTypeObject *type);
|
|
93
|
+
|
|
94
|
+
// Band-aid workaround to fix a subtle but serious bug in a minimalistic fashion. See PR #4762.
|
|
95
|
+
inline void all_type_info_add_base_most_derived_first(std::vector<type_info *> &bases,
|
|
96
|
+
type_info *addl_base) {
|
|
97
|
+
for (auto it = bases.begin(); it != bases.end(); it++) {
|
|
98
|
+
type_info *existing_base = *it;
|
|
99
|
+
if (PyType_IsSubtype(addl_base->type, existing_base->type) != 0) {
|
|
100
|
+
bases.insert(it, addl_base);
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
bases.push_back(addl_base);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// Populates a just-created cache entry.
|
|
108
|
+
PYBIND11_NOINLINE void all_type_info_populate(PyTypeObject *t, std::vector<type_info *> &bases) {
|
|
109
|
+
assert(bases.empty());
|
|
110
|
+
std::vector<PyTypeObject *> check;
|
|
111
|
+
for (handle parent : reinterpret_borrow<tuple>(t->tp_bases)) {
|
|
112
|
+
check.push_back((PyTypeObject *) parent.ptr());
|
|
113
|
+
}
|
|
114
|
+
auto const &type_dict = get_internals().registered_types_py;
|
|
115
|
+
for (size_t i = 0; i < check.size(); i++) {
|
|
116
|
+
auto *type = check[i];
|
|
117
|
+
// Ignore Python2 old-style class super type:
|
|
118
|
+
if (!PyType_Check((PyObject *) type)) {
|
|
119
|
+
continue;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// Check `type` in the current set of registered python types:
|
|
123
|
+
auto it = type_dict.find(type);
|
|
124
|
+
if (it != type_dict.end()) {
|
|
125
|
+
// We found a cache entry for it, so it's either pybind-registered or has pre-computed
|
|
126
|
+
// pybind bases, but we have to make sure we haven't already seen the type(s) before:
|
|
127
|
+
// we want to follow Python/virtual C++ rules that there should only be one instance of
|
|
128
|
+
// a common base.
|
|
129
|
+
for (auto *tinfo : it->second) {
|
|
130
|
+
// NB: Could use a second set here, rather than doing a linear search, but since
|
|
131
|
+
// having a large number of immediate pybind11-registered types seems fairly
|
|
132
|
+
// unlikely, that probably isn't worthwhile.
|
|
133
|
+
bool found = false;
|
|
134
|
+
for (auto *known : bases) {
|
|
135
|
+
if (known == tinfo) {
|
|
136
|
+
found = true;
|
|
137
|
+
break;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
if (!found) {
|
|
141
|
+
all_type_info_add_base_most_derived_first(bases, tinfo);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
} else if (type->tp_bases) {
|
|
145
|
+
// It's some python type, so keep follow its bases classes to look for one or more
|
|
146
|
+
// registered types
|
|
147
|
+
if (i + 1 == check.size()) {
|
|
148
|
+
// When we're at the end, we can pop off the current element to avoid growing
|
|
149
|
+
// `check` when adding just one base (which is typical--i.e. when there is no
|
|
150
|
+
// multiple inheritance)
|
|
151
|
+
check.pop_back();
|
|
152
|
+
i--;
|
|
153
|
+
}
|
|
154
|
+
for (handle parent : reinterpret_borrow<tuple>(type->tp_bases)) {
|
|
155
|
+
check.push_back((PyTypeObject *) parent.ptr());
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* Extracts vector of type_info pointers of pybind-registered roots of the given Python type. Will
|
|
163
|
+
* be just 1 pybind type for the Python type of a pybind-registered class, or for any Python-side
|
|
164
|
+
* derived class that uses single inheritance. Will contain as many types as required for a Python
|
|
165
|
+
* class that uses multiple inheritance to inherit (directly or indirectly) from multiple
|
|
166
|
+
* pybind-registered classes. Will be empty if neither the type nor any base classes are
|
|
167
|
+
* pybind-registered.
|
|
168
|
+
*
|
|
169
|
+
* The value is cached for the lifetime of the Python type.
|
|
170
|
+
*/
|
|
171
|
+
inline const std::vector<detail::type_info *> &all_type_info(PyTypeObject *type) {
|
|
172
|
+
return all_type_info_get_cache(type).first->second;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
/**
|
|
176
|
+
* Gets a single pybind11 type info for a python type. Returns nullptr if neither the type nor any
|
|
177
|
+
* ancestors are pybind11-registered. Throws an exception if there are multiple bases--use
|
|
178
|
+
* `all_type_info` instead if you want to support multiple bases.
|
|
179
|
+
*/
|
|
180
|
+
PYBIND11_NOINLINE detail::type_info *get_type_info(PyTypeObject *type) {
|
|
181
|
+
const auto &bases = all_type_info(type);
|
|
182
|
+
if (bases.empty()) {
|
|
183
|
+
return nullptr;
|
|
184
|
+
}
|
|
185
|
+
if (bases.size() > 1) {
|
|
186
|
+
pybind11_fail(
|
|
187
|
+
"pybind11::detail::get_type_info: type has multiple pybind11-registered bases");
|
|
188
|
+
}
|
|
189
|
+
return bases.front();
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
inline detail::type_info *get_local_type_info(const std::type_index &tp) {
|
|
193
|
+
auto &locals = get_local_internals().registered_types_cpp;
|
|
194
|
+
auto it = locals.find(tp);
|
|
195
|
+
if (it != locals.end()) {
|
|
196
|
+
return it->second;
|
|
197
|
+
}
|
|
198
|
+
return nullptr;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
inline detail::type_info *get_global_type_info(const std::type_index &tp) {
|
|
202
|
+
return with_internals([&](internals &internals) {
|
|
203
|
+
detail::type_info *type_info = nullptr;
|
|
204
|
+
auto &types = internals.registered_types_cpp;
|
|
205
|
+
auto it = types.find(tp);
|
|
206
|
+
if (it != types.end()) {
|
|
207
|
+
type_info = it->second;
|
|
208
|
+
}
|
|
209
|
+
return type_info;
|
|
210
|
+
});
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
/// Return the type info for a given C++ type; on lookup failure can either throw or return
|
|
214
|
+
/// nullptr.
|
|
215
|
+
PYBIND11_NOINLINE detail::type_info *get_type_info(const std::type_index &tp,
|
|
216
|
+
bool throw_if_missing = false) {
|
|
217
|
+
if (auto *ltype = get_local_type_info(tp)) {
|
|
218
|
+
return ltype;
|
|
219
|
+
}
|
|
220
|
+
if (auto *gtype = get_global_type_info(tp)) {
|
|
221
|
+
return gtype;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
if (throw_if_missing) {
|
|
225
|
+
std::string tname = tp.name();
|
|
226
|
+
detail::clean_type_id(tname);
|
|
227
|
+
pybind11_fail("pybind11::detail::get_type_info: unable to find type info for \""
|
|
228
|
+
+ std::move(tname) + '"');
|
|
229
|
+
}
|
|
230
|
+
return nullptr;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
PYBIND11_NOINLINE handle get_type_handle(const std::type_info &tp, bool throw_if_missing) {
|
|
234
|
+
detail::type_info *type_info = get_type_info(tp, throw_if_missing);
|
|
235
|
+
return handle(type_info ? ((PyObject *) type_info->type) : nullptr);
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
inline bool try_incref(PyObject *obj) {
|
|
239
|
+
// Tries to increment the reference count of an object if it's not zero.
|
|
240
|
+
// TODO: Use PyUnstable_TryIncref when available.
|
|
241
|
+
// See https://github.com/python/cpython/issues/128844
|
|
242
|
+
#ifdef Py_GIL_DISABLED
|
|
243
|
+
// See
|
|
244
|
+
// https://github.com/python/cpython/blob/d05140f9f77d7dfc753dd1e5ac3a5962aaa03eff/Include/internal/pycore_object.h#L761
|
|
245
|
+
uint32_t local = _Py_atomic_load_uint32_relaxed(&obj->ob_ref_local);
|
|
246
|
+
local += 1;
|
|
247
|
+
if (local == 0) {
|
|
248
|
+
// immortal
|
|
249
|
+
return true;
|
|
250
|
+
}
|
|
251
|
+
if (_Py_IsOwnedByCurrentThread(obj)) {
|
|
252
|
+
_Py_atomic_store_uint32_relaxed(&obj->ob_ref_local, local);
|
|
253
|
+
# ifdef Py_REF_DEBUG
|
|
254
|
+
_Py_INCREF_IncRefTotal();
|
|
255
|
+
# endif
|
|
256
|
+
return true;
|
|
257
|
+
}
|
|
258
|
+
Py_ssize_t shared = _Py_atomic_load_ssize_relaxed(&obj->ob_ref_shared);
|
|
259
|
+
for (;;) {
|
|
260
|
+
// If the shared refcount is zero and the object is either merged
|
|
261
|
+
// or may not have weak references, then we cannot incref it.
|
|
262
|
+
if (shared == 0 || shared == _Py_REF_MERGED) {
|
|
263
|
+
return false;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
if (_Py_atomic_compare_exchange_ssize(
|
|
267
|
+
&obj->ob_ref_shared, &shared, shared + (1 << _Py_REF_SHARED_SHIFT))) {
|
|
268
|
+
# ifdef Py_REF_DEBUG
|
|
269
|
+
_Py_INCREF_IncRefTotal();
|
|
270
|
+
# endif
|
|
271
|
+
return true;
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
#else
|
|
275
|
+
assert(Py_REFCNT(obj) > 0);
|
|
276
|
+
Py_INCREF(obj);
|
|
277
|
+
return true;
|
|
278
|
+
#endif
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
// Searches the inheritance graph for a registered Python instance, using all_type_info().
|
|
282
|
+
PYBIND11_NOINLINE handle find_registered_python_instance(void *src,
|
|
283
|
+
const detail::type_info *tinfo) {
|
|
284
|
+
return with_instance_map(src, [&](instance_map &instances) {
|
|
285
|
+
auto it_instances = instances.equal_range(src);
|
|
286
|
+
for (auto it_i = it_instances.first; it_i != it_instances.second; ++it_i) {
|
|
287
|
+
for (auto *instance_type : detail::all_type_info(Py_TYPE(it_i->second))) {
|
|
288
|
+
if (instance_type && same_type(*instance_type->cpptype, *tinfo->cpptype)) {
|
|
289
|
+
auto *wrapper = reinterpret_cast<PyObject *>(it_i->second);
|
|
290
|
+
if (try_incref(wrapper)) {
|
|
291
|
+
return handle(wrapper);
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
return handle();
|
|
297
|
+
});
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
// Container for accessing and iterating over an instance's values/holders
|
|
301
|
+
struct values_and_holders {
|
|
302
|
+
private:
|
|
303
|
+
instance *inst;
|
|
304
|
+
using type_vec = std::vector<detail::type_info *>;
|
|
305
|
+
const type_vec &tinfo;
|
|
306
|
+
|
|
307
|
+
public:
|
|
308
|
+
explicit values_and_holders(instance *inst)
|
|
309
|
+
: inst{inst}, tinfo(all_type_info(Py_TYPE(inst))) {}
|
|
310
|
+
|
|
311
|
+
explicit values_and_holders(PyObject *obj)
|
|
312
|
+
: inst{nullptr}, tinfo(all_type_info(Py_TYPE(obj))) {
|
|
313
|
+
if (!tinfo.empty()) {
|
|
314
|
+
inst = reinterpret_cast<instance *>(obj);
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
struct iterator {
|
|
319
|
+
private:
|
|
320
|
+
instance *inst = nullptr;
|
|
321
|
+
const type_vec *types = nullptr;
|
|
322
|
+
value_and_holder curr;
|
|
323
|
+
friend struct values_and_holders;
|
|
324
|
+
iterator(instance *inst, const type_vec *tinfo) : inst{inst}, types{tinfo} {
|
|
325
|
+
if (inst != nullptr) {
|
|
326
|
+
assert(!types->empty());
|
|
327
|
+
curr = value_and_holder(
|
|
328
|
+
inst /* instance */,
|
|
329
|
+
(*types)[0] /* type info */,
|
|
330
|
+
0, /* vpos: (non-simple types only): the first vptr comes first */
|
|
331
|
+
0 /* index */);
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
// Past-the-end iterator:
|
|
335
|
+
explicit iterator(size_t end) : curr(end) {}
|
|
336
|
+
|
|
337
|
+
public:
|
|
338
|
+
bool operator==(const iterator &other) const { return curr.index == other.curr.index; }
|
|
339
|
+
bool operator!=(const iterator &other) const { return curr.index != other.curr.index; }
|
|
340
|
+
iterator &operator++() {
|
|
341
|
+
if (!inst->simple_layout) {
|
|
342
|
+
curr.vh += 1 + (*types)[curr.index]->holder_size_in_ptrs;
|
|
343
|
+
}
|
|
344
|
+
++curr.index;
|
|
345
|
+
curr.type = curr.index < types->size() ? (*types)[curr.index] : nullptr;
|
|
346
|
+
return *this;
|
|
347
|
+
}
|
|
348
|
+
value_and_holder &operator*() { return curr; }
|
|
349
|
+
value_and_holder *operator->() { return &curr; }
|
|
350
|
+
};
|
|
351
|
+
|
|
352
|
+
iterator begin() { return iterator(inst, &tinfo); }
|
|
353
|
+
iterator end() { return iterator(tinfo.size()); }
|
|
354
|
+
|
|
355
|
+
iterator find(const type_info *find_type) {
|
|
356
|
+
auto it = begin(), endit = end();
|
|
357
|
+
while (it != endit && it->type != find_type) {
|
|
358
|
+
++it;
|
|
359
|
+
}
|
|
360
|
+
return it;
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
size_t size() { return tinfo.size(); }
|
|
364
|
+
|
|
365
|
+
// Band-aid workaround to fix a subtle but serious bug in a minimalistic fashion. See PR #4762.
|
|
366
|
+
bool is_redundant_value_and_holder(const value_and_holder &vh) {
|
|
367
|
+
for (size_t i = 0; i < vh.index; i++) {
|
|
368
|
+
if (PyType_IsSubtype(tinfo[i]->type, tinfo[vh.index]->type) != 0) {
|
|
369
|
+
return true;
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
return false;
|
|
373
|
+
}
|
|
374
|
+
};
|
|
375
|
+
|
|
376
|
+
/**
|
|
377
|
+
* Extracts C++ value and holder pointer references from an instance (which may contain multiple
|
|
378
|
+
* values/holders for python-side multiple inheritance) that match the given type. Throws an error
|
|
379
|
+
* if the given type (or ValueType, if omitted) is not a pybind11 base of the given instance. If
|
|
380
|
+
* `find_type` is omitted (or explicitly specified as nullptr) the first value/holder are returned,
|
|
381
|
+
* regardless of type (and the resulting .type will be nullptr).
|
|
382
|
+
*
|
|
383
|
+
* The returned object should be short-lived: in particular, it must not outlive the called-upon
|
|
384
|
+
* instance.
|
|
385
|
+
*/
|
|
386
|
+
PYBIND11_NOINLINE value_and_holder
|
|
387
|
+
instance::get_value_and_holder(const type_info *find_type /*= nullptr default in common.h*/,
|
|
388
|
+
bool throw_if_missing /*= true in common.h*/) {
|
|
389
|
+
// Optimize common case:
|
|
390
|
+
if (!find_type || Py_TYPE(this) == find_type->type) {
|
|
391
|
+
return value_and_holder(this, find_type, 0, 0);
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
detail::values_and_holders vhs(this);
|
|
395
|
+
auto it = vhs.find(find_type);
|
|
396
|
+
if (it != vhs.end()) {
|
|
397
|
+
return *it;
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
if (!throw_if_missing) {
|
|
401
|
+
return value_and_holder();
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
#if defined(PYBIND11_DETAILED_ERROR_MESSAGES)
|
|
405
|
+
pybind11_fail("pybind11::detail::instance::get_value_and_holder: `"
|
|
406
|
+
+ get_fully_qualified_tp_name(find_type->type)
|
|
407
|
+
+ "' is not a pybind11 base of the given `"
|
|
408
|
+
+ get_fully_qualified_tp_name(Py_TYPE(this)) + "' instance");
|
|
409
|
+
#else
|
|
410
|
+
pybind11_fail(
|
|
411
|
+
"pybind11::detail::instance::get_value_and_holder: "
|
|
412
|
+
"type is not a pybind11 base of the given instance "
|
|
413
|
+
"(#define PYBIND11_DETAILED_ERROR_MESSAGES or compile in debug mode for type details)");
|
|
414
|
+
#endif
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
PYBIND11_NOINLINE void instance::allocate_layout() {
|
|
418
|
+
const auto &tinfo = all_type_info(Py_TYPE(this));
|
|
419
|
+
|
|
420
|
+
const size_t n_types = tinfo.size();
|
|
421
|
+
|
|
422
|
+
if (n_types == 0) {
|
|
423
|
+
pybind11_fail(
|
|
424
|
+
"instance allocation failed: new instance has no pybind11-registered base types");
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
simple_layout
|
|
428
|
+
= n_types == 1 && tinfo.front()->holder_size_in_ptrs <= instance_simple_holder_in_ptrs();
|
|
429
|
+
|
|
430
|
+
// Simple path: no python-side multiple inheritance, and a small-enough holder
|
|
431
|
+
if (simple_layout) {
|
|
432
|
+
simple_value_holder[0] = nullptr;
|
|
433
|
+
simple_holder_constructed = false;
|
|
434
|
+
simple_instance_registered = false;
|
|
435
|
+
} else { // multiple base types or a too-large holder
|
|
436
|
+
// Allocate space to hold: [v1*][h1][v2*][h2]...[bb...] where [vN*] is a value pointer,
|
|
437
|
+
// [hN] is the (uninitialized) holder instance for value N, and [bb...] is a set of bool
|
|
438
|
+
// values that tracks whether each associated holder has been initialized. Each [block] is
|
|
439
|
+
// padded, if necessary, to an integer multiple of sizeof(void *).
|
|
440
|
+
size_t space = 0;
|
|
441
|
+
for (auto *t : tinfo) {
|
|
442
|
+
space += 1; // value pointer
|
|
443
|
+
space += t->holder_size_in_ptrs; // holder instance
|
|
444
|
+
}
|
|
445
|
+
size_t flags_at = space;
|
|
446
|
+
space += size_in_ptrs(n_types); // status bytes (holder_constructed and
|
|
447
|
+
// instance_registered)
|
|
448
|
+
|
|
449
|
+
// Allocate space for flags, values, and holders, and initialize it to 0 (flags and values,
|
|
450
|
+
// in particular, need to be 0). Use Python's memory allocation
|
|
451
|
+
// functions: Python is using pymalloc, which is designed to be
|
|
452
|
+
// efficient for small allocations like the one we're doing here;
|
|
453
|
+
// for larger allocations they are just wrappers around malloc.
|
|
454
|
+
// TODO: is this still true for pure Python 3.6?
|
|
455
|
+
nonsimple.values_and_holders = (void **) PyMem_Calloc(space, sizeof(void *));
|
|
456
|
+
if (!nonsimple.values_and_holders) {
|
|
457
|
+
throw std::bad_alloc();
|
|
458
|
+
}
|
|
459
|
+
nonsimple.status
|
|
460
|
+
= reinterpret_cast<std::uint8_t *>(&nonsimple.values_and_holders[flags_at]);
|
|
461
|
+
}
|
|
462
|
+
owned = true;
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
// NOLINTNEXTLINE(readability-make-member-function-const)
|
|
466
|
+
PYBIND11_NOINLINE void instance::deallocate_layout() {
|
|
467
|
+
if (!simple_layout) {
|
|
468
|
+
PyMem_Free(reinterpret_cast<void *>(nonsimple.values_and_holders));
|
|
469
|
+
}
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
PYBIND11_NOINLINE bool isinstance_generic(handle obj, const std::type_info &tp) {
|
|
473
|
+
handle type = detail::get_type_handle(tp, false);
|
|
474
|
+
if (!type) {
|
|
475
|
+
return false;
|
|
476
|
+
}
|
|
477
|
+
return isinstance(obj, type);
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
PYBIND11_NOINLINE handle get_object_handle(const void *ptr, const detail::type_info *type) {
|
|
481
|
+
return with_instance_map(ptr, [&](instance_map &instances) {
|
|
482
|
+
auto range = instances.equal_range(ptr);
|
|
483
|
+
for (auto it = range.first; it != range.second; ++it) {
|
|
484
|
+
for (const auto &vh : values_and_holders(it->second)) {
|
|
485
|
+
if (vh.type == type) {
|
|
486
|
+
return handle((PyObject *) it->second);
|
|
487
|
+
}
|
|
488
|
+
}
|
|
489
|
+
}
|
|
490
|
+
return handle();
|
|
491
|
+
});
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
// Forward declarations
|
|
495
|
+
void keep_alive_impl(handle nurse, handle patient);
|
|
496
|
+
inline PyObject *make_new_instance(PyTypeObject *type);
|
|
497
|
+
|
|
498
|
+
PYBIND11_WARNING_PUSH
|
|
499
|
+
PYBIND11_WARNING_DISABLE_GCC("-Wredundant-decls")
|
|
500
|
+
|
|
501
|
+
// PYBIND11:REMINDER: Needs refactoring of existing pybind11 code.
|
|
502
|
+
inline bool deregister_instance(instance *self, void *valptr, const type_info *tinfo);
|
|
503
|
+
|
|
504
|
+
PYBIND11_WARNING_POP
|
|
505
|
+
|
|
506
|
+
PYBIND11_NAMESPACE_BEGIN(smart_holder_type_caster_support)
|
|
507
|
+
|
|
508
|
+
struct value_and_holder_helper {
|
|
509
|
+
value_and_holder loaded_v_h;
|
|
510
|
+
|
|
511
|
+
bool have_holder() const {
|
|
512
|
+
return loaded_v_h.vh != nullptr && loaded_v_h.holder_constructed();
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
smart_holder &holder() const { return loaded_v_h.holder<smart_holder>(); }
|
|
516
|
+
|
|
517
|
+
void throw_if_uninitialized_or_disowned_holder(const char *typeid_name) const {
|
|
518
|
+
static const std::string missing_value_msg = "Missing value for wrapped C++ type `";
|
|
519
|
+
if (!holder().is_populated) {
|
|
520
|
+
throw value_error(missing_value_msg + clean_type_id(typeid_name)
|
|
521
|
+
+ "`: Python instance is uninitialized.");
|
|
522
|
+
}
|
|
523
|
+
if (!holder().has_pointee()) {
|
|
524
|
+
throw value_error(missing_value_msg + clean_type_id(typeid_name)
|
|
525
|
+
+ "`: Python instance was disowned.");
|
|
526
|
+
}
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
void throw_if_uninitialized_or_disowned_holder(const std::type_info &type_info) const {
|
|
530
|
+
throw_if_uninitialized_or_disowned_holder(type_info.name());
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
// have_holder() must be true or this function will fail.
|
|
534
|
+
void throw_if_instance_is_currently_owned_by_shared_ptr(const type_info *tinfo) const {
|
|
535
|
+
auto *vptr_gd_ptr = tinfo->get_memory_guarded_delete(holder().vptr);
|
|
536
|
+
if (vptr_gd_ptr != nullptr && !vptr_gd_ptr->released_ptr.expired()) {
|
|
537
|
+
throw value_error("Python instance is currently owned by a std::shared_ptr.");
|
|
538
|
+
}
|
|
539
|
+
}
|
|
540
|
+
|
|
541
|
+
void *get_void_ptr_or_nullptr() const {
|
|
542
|
+
if (have_holder()) {
|
|
543
|
+
auto &hld = holder();
|
|
544
|
+
if (hld.is_populated && hld.has_pointee()) {
|
|
545
|
+
return hld.template as_raw_ptr_unowned<void>();
|
|
546
|
+
}
|
|
547
|
+
}
|
|
548
|
+
return nullptr;
|
|
549
|
+
}
|
|
550
|
+
};
|
|
551
|
+
|
|
552
|
+
template <typename T, typename D>
|
|
553
|
+
handle smart_holder_from_unique_ptr(std::unique_ptr<T, D> &&src,
|
|
554
|
+
return_value_policy policy,
|
|
555
|
+
handle parent,
|
|
556
|
+
const std::pair<const void *, const type_info *> &st) {
|
|
557
|
+
if (policy == return_value_policy::copy) {
|
|
558
|
+
throw cast_error("return_value_policy::copy is invalid for unique_ptr.");
|
|
559
|
+
}
|
|
560
|
+
if (!src) {
|
|
561
|
+
return none().release();
|
|
562
|
+
}
|
|
563
|
+
void *src_raw_void_ptr = const_cast<void *>(st.first);
|
|
564
|
+
assert(st.second != nullptr);
|
|
565
|
+
const detail::type_info *tinfo = st.second;
|
|
566
|
+
if (handle existing_inst = find_registered_python_instance(src_raw_void_ptr, tinfo)) {
|
|
567
|
+
auto *self_life_support = tinfo->get_trampoline_self_life_support(src.get());
|
|
568
|
+
if (self_life_support != nullptr) {
|
|
569
|
+
value_and_holder &v_h = self_life_support->v_h;
|
|
570
|
+
if (v_h.inst != nullptr && v_h.vh != nullptr) {
|
|
571
|
+
auto &holder = v_h.holder<smart_holder>();
|
|
572
|
+
if (!holder.is_disowned) {
|
|
573
|
+
pybind11_fail("smart_holder_from_unique_ptr: unexpected "
|
|
574
|
+
"smart_holder.is_disowned failure.");
|
|
575
|
+
}
|
|
576
|
+
// Critical transfer-of-ownership section. This must stay together.
|
|
577
|
+
self_life_support->deactivate_life_support();
|
|
578
|
+
holder.reclaim_disowned(tinfo->get_memory_guarded_delete);
|
|
579
|
+
(void) src.release();
|
|
580
|
+
// Critical section end.
|
|
581
|
+
return existing_inst;
|
|
582
|
+
}
|
|
583
|
+
}
|
|
584
|
+
throw cast_error("Invalid unique_ptr: another instance owns this pointer already.");
|
|
585
|
+
}
|
|
586
|
+
|
|
587
|
+
auto inst = reinterpret_steal<object>(make_new_instance(tinfo->type));
|
|
588
|
+
auto *inst_raw_ptr = reinterpret_cast<instance *>(inst.ptr());
|
|
589
|
+
inst_raw_ptr->owned = true;
|
|
590
|
+
void *&valueptr = values_and_holders(inst_raw_ptr).begin()->value_ptr();
|
|
591
|
+
valueptr = src_raw_void_ptr;
|
|
592
|
+
|
|
593
|
+
if (static_cast<void *>(src.get()) == src_raw_void_ptr) {
|
|
594
|
+
// This is a multiple-inheritance situation that is incompatible with the current
|
|
595
|
+
// shared_from_this handling (see PR #3023). Is there a better solution?
|
|
596
|
+
src_raw_void_ptr = nullptr;
|
|
597
|
+
}
|
|
598
|
+
auto smhldr = smart_holder::from_unique_ptr(std::move(src), src_raw_void_ptr);
|
|
599
|
+
tinfo->init_instance(inst_raw_ptr, static_cast<const void *>(&smhldr));
|
|
600
|
+
|
|
601
|
+
if (policy == return_value_policy::reference_internal) {
|
|
602
|
+
keep_alive_impl(inst, parent);
|
|
603
|
+
}
|
|
604
|
+
|
|
605
|
+
return inst.release();
|
|
606
|
+
}
|
|
607
|
+
|
|
608
|
+
template <typename T, typename D>
|
|
609
|
+
handle smart_holder_from_unique_ptr(std::unique_ptr<T const, D> &&src,
|
|
610
|
+
return_value_policy policy,
|
|
611
|
+
handle parent,
|
|
612
|
+
const std::pair<const void *, const type_info *> &st) {
|
|
613
|
+
return smart_holder_from_unique_ptr(
|
|
614
|
+
std::unique_ptr<T, D>(const_cast<T *>(src.release()),
|
|
615
|
+
std::move(src.get_deleter())), // Const2Mutbl
|
|
616
|
+
policy,
|
|
617
|
+
parent,
|
|
618
|
+
st);
|
|
619
|
+
}
|
|
620
|
+
|
|
621
|
+
template <typename T>
|
|
622
|
+
handle smart_holder_from_shared_ptr(const std::shared_ptr<T> &src,
|
|
623
|
+
return_value_policy policy,
|
|
624
|
+
handle parent,
|
|
625
|
+
const std::pair<const void *, const type_info *> &st) {
|
|
626
|
+
switch (policy) {
|
|
627
|
+
case return_value_policy::automatic:
|
|
628
|
+
case return_value_policy::automatic_reference:
|
|
629
|
+
break;
|
|
630
|
+
case return_value_policy::take_ownership:
|
|
631
|
+
throw cast_error("Invalid return_value_policy for shared_ptr (take_ownership).");
|
|
632
|
+
case return_value_policy::copy:
|
|
633
|
+
case return_value_policy::move:
|
|
634
|
+
break;
|
|
635
|
+
case return_value_policy::reference:
|
|
636
|
+
throw cast_error("Invalid return_value_policy for shared_ptr (reference).");
|
|
637
|
+
case return_value_policy::reference_internal:
|
|
638
|
+
break;
|
|
639
|
+
}
|
|
640
|
+
if (!src) {
|
|
641
|
+
return none().release();
|
|
642
|
+
}
|
|
643
|
+
|
|
644
|
+
auto src_raw_ptr = src.get();
|
|
645
|
+
assert(st.second != nullptr);
|
|
646
|
+
void *src_raw_void_ptr = static_cast<void *>(src_raw_ptr);
|
|
647
|
+
const detail::type_info *tinfo = st.second;
|
|
648
|
+
if (handle existing_inst = find_registered_python_instance(src_raw_void_ptr, tinfo)) {
|
|
649
|
+
// PYBIND11:REMINDER: MISSING: Enforcement of consistency with existing smart_holder.
|
|
650
|
+
// PYBIND11:REMINDER: MISSING: keep_alive.
|
|
651
|
+
return existing_inst;
|
|
652
|
+
}
|
|
653
|
+
|
|
654
|
+
auto inst = reinterpret_steal<object>(make_new_instance(tinfo->type));
|
|
655
|
+
auto *inst_raw_ptr = reinterpret_cast<instance *>(inst.ptr());
|
|
656
|
+
inst_raw_ptr->owned = true;
|
|
657
|
+
void *&valueptr = values_and_holders(inst_raw_ptr).begin()->value_ptr();
|
|
658
|
+
valueptr = src_raw_void_ptr;
|
|
659
|
+
|
|
660
|
+
auto smhldr
|
|
661
|
+
= smart_holder::from_shared_ptr(std::shared_ptr<void>(src, const_cast<void *>(st.first)));
|
|
662
|
+
tinfo->init_instance(inst_raw_ptr, static_cast<const void *>(&smhldr));
|
|
663
|
+
|
|
664
|
+
if (policy == return_value_policy::reference_internal) {
|
|
665
|
+
keep_alive_impl(inst, parent);
|
|
666
|
+
}
|
|
667
|
+
|
|
668
|
+
return inst.release();
|
|
669
|
+
}
|
|
670
|
+
|
|
671
|
+
template <typename T>
|
|
672
|
+
handle smart_holder_from_shared_ptr(const std::shared_ptr<T const> &src,
|
|
673
|
+
return_value_policy policy,
|
|
674
|
+
handle parent,
|
|
675
|
+
const std::pair<const void *, const type_info *> &st) {
|
|
676
|
+
return smart_holder_from_shared_ptr(std::const_pointer_cast<T>(src), // Const2Mutbl
|
|
677
|
+
policy,
|
|
678
|
+
parent,
|
|
679
|
+
st);
|
|
680
|
+
}
|
|
681
|
+
|
|
682
|
+
struct shared_ptr_parent_life_support {
|
|
683
|
+
PyObject *parent;
|
|
684
|
+
explicit shared_ptr_parent_life_support(PyObject *parent) : parent{parent} {
|
|
685
|
+
Py_INCREF(parent);
|
|
686
|
+
}
|
|
687
|
+
// NOLINTNEXTLINE(readability-make-member-function-const)
|
|
688
|
+
void operator()(void *) {
|
|
689
|
+
gil_scoped_acquire gil;
|
|
690
|
+
Py_DECREF(parent);
|
|
691
|
+
}
|
|
692
|
+
};
|
|
693
|
+
|
|
694
|
+
struct shared_ptr_trampoline_self_life_support {
|
|
695
|
+
PyObject *self;
|
|
696
|
+
explicit shared_ptr_trampoline_self_life_support(instance *inst)
|
|
697
|
+
: self{reinterpret_cast<PyObject *>(inst)} {
|
|
698
|
+
gil_scoped_acquire gil;
|
|
699
|
+
Py_INCREF(self);
|
|
700
|
+
}
|
|
701
|
+
// NOLINTNEXTLINE(readability-make-member-function-const)
|
|
702
|
+
void operator()(void *) {
|
|
703
|
+
gil_scoped_acquire gil;
|
|
704
|
+
Py_DECREF(self);
|
|
705
|
+
}
|
|
706
|
+
};
|
|
707
|
+
|
|
708
|
+
template <typename T,
|
|
709
|
+
typename D,
|
|
710
|
+
typename std::enable_if<std::is_default_constructible<D>::value, int>::type = 0>
|
|
711
|
+
inline std::unique_ptr<T, D> unique_with_deleter(T *raw_ptr, std::unique_ptr<D> &&deleter) {
|
|
712
|
+
if (deleter == nullptr) {
|
|
713
|
+
return std::unique_ptr<T, D>(raw_ptr);
|
|
714
|
+
}
|
|
715
|
+
return std::unique_ptr<T, D>(raw_ptr, std::move(*deleter));
|
|
716
|
+
}
|
|
717
|
+
|
|
718
|
+
template <typename T,
|
|
719
|
+
typename D,
|
|
720
|
+
typename std::enable_if<!std::is_default_constructible<D>::value, int>::type = 0>
|
|
721
|
+
inline std::unique_ptr<T, D> unique_with_deleter(T *raw_ptr, std::unique_ptr<D> &&deleter) {
|
|
722
|
+
if (deleter == nullptr) {
|
|
723
|
+
pybind11_fail("smart_holder_type_casters: deleter is not default constructible and no"
|
|
724
|
+
" instance available to return.");
|
|
725
|
+
}
|
|
726
|
+
return std::unique_ptr<T, D>(raw_ptr, std::move(*deleter));
|
|
727
|
+
}
|
|
728
|
+
|
|
729
|
+
template <typename T>
|
|
730
|
+
struct load_helper : value_and_holder_helper {
|
|
731
|
+
bool was_populated = false;
|
|
732
|
+
bool python_instance_is_alias = false;
|
|
733
|
+
|
|
734
|
+
void maybe_set_python_instance_is_alias(handle src) {
|
|
735
|
+
if (was_populated) {
|
|
736
|
+
python_instance_is_alias = reinterpret_cast<instance *>(src.ptr())->is_alias;
|
|
737
|
+
}
|
|
738
|
+
}
|
|
739
|
+
|
|
740
|
+
static std::shared_ptr<T> make_shared_ptr_with_responsible_parent(T *raw_ptr, handle parent) {
|
|
741
|
+
return std::shared_ptr<T>(raw_ptr, shared_ptr_parent_life_support(parent.ptr()));
|
|
742
|
+
}
|
|
743
|
+
|
|
744
|
+
std::shared_ptr<T> load_as_shared_ptr(const type_info *tinfo,
|
|
745
|
+
void *void_raw_ptr,
|
|
746
|
+
handle responsible_parent = nullptr,
|
|
747
|
+
// to support py::potentially_slicing_weak_ptr
|
|
748
|
+
// with minimal added code complexity:
|
|
749
|
+
bool force_potentially_slicing_shared_ptr
|
|
750
|
+
= false) const {
|
|
751
|
+
if (!have_holder()) {
|
|
752
|
+
return nullptr;
|
|
753
|
+
}
|
|
754
|
+
throw_if_uninitialized_or_disowned_holder(typeid(T));
|
|
755
|
+
smart_holder &hld = holder();
|
|
756
|
+
hld.ensure_is_not_disowned("load_as_shared_ptr");
|
|
757
|
+
if (hld.vptr_is_using_noop_deleter) {
|
|
758
|
+
if (responsible_parent) {
|
|
759
|
+
return make_shared_ptr_with_responsible_parent(static_cast<T *>(void_raw_ptr),
|
|
760
|
+
responsible_parent);
|
|
761
|
+
}
|
|
762
|
+
throw std::runtime_error("Non-owning holder (load_as_shared_ptr).");
|
|
763
|
+
}
|
|
764
|
+
auto *type_raw_ptr = static_cast<T *>(void_raw_ptr);
|
|
765
|
+
if (python_instance_is_alias && !force_potentially_slicing_shared_ptr) {
|
|
766
|
+
auto *vptr_gd_ptr = tinfo->get_memory_guarded_delete(holder().vptr);
|
|
767
|
+
if (vptr_gd_ptr != nullptr) {
|
|
768
|
+
std::shared_ptr<void> released_ptr = vptr_gd_ptr->released_ptr.lock();
|
|
769
|
+
if (released_ptr) {
|
|
770
|
+
return std::shared_ptr<T>(released_ptr, type_raw_ptr);
|
|
771
|
+
}
|
|
772
|
+
std::shared_ptr<T> to_be_released(
|
|
773
|
+
type_raw_ptr, shared_ptr_trampoline_self_life_support(loaded_v_h.inst));
|
|
774
|
+
vptr_gd_ptr->released_ptr = to_be_released;
|
|
775
|
+
return to_be_released;
|
|
776
|
+
}
|
|
777
|
+
auto *sptsls_ptr = std::get_deleter<shared_ptr_trampoline_self_life_support>(hld.vptr);
|
|
778
|
+
if (sptsls_ptr != nullptr) {
|
|
779
|
+
// This code is reachable only if there are multiple registered_instances for the
|
|
780
|
+
// same pointee.
|
|
781
|
+
if (reinterpret_cast<PyObject *>(loaded_v_h.inst) == sptsls_ptr->self) {
|
|
782
|
+
pybind11_fail("smart_holder_type_caster_support load_as_shared_ptr failure: "
|
|
783
|
+
"loaded_v_h.inst == sptsls_ptr->self");
|
|
784
|
+
}
|
|
785
|
+
}
|
|
786
|
+
if (sptsls_ptr != nullptr || !memory::type_has_shared_from_this(type_raw_ptr)) {
|
|
787
|
+
return std::shared_ptr<T>(
|
|
788
|
+
type_raw_ptr, shared_ptr_trampoline_self_life_support(loaded_v_h.inst));
|
|
789
|
+
}
|
|
790
|
+
if (hld.vptr_is_external_shared_ptr) {
|
|
791
|
+
pybind11_fail("smart_holder_type_casters load_as_shared_ptr failure: not "
|
|
792
|
+
"implemented: trampoline-self-life-support for external shared_ptr "
|
|
793
|
+
"to type inheriting from std::enable_shared_from_this.");
|
|
794
|
+
}
|
|
795
|
+
pybind11_fail(
|
|
796
|
+
"smart_holder_type_casters: load_as_shared_ptr failure: internal inconsistency.");
|
|
797
|
+
}
|
|
798
|
+
std::shared_ptr<void> void_shd_ptr = hld.template as_shared_ptr<void>();
|
|
799
|
+
return std::shared_ptr<T>(void_shd_ptr, type_raw_ptr);
|
|
800
|
+
}
|
|
801
|
+
|
|
802
|
+
template <typename D>
|
|
803
|
+
std::unique_ptr<T, D> load_as_unique_ptr(const type_info *tinfo,
|
|
804
|
+
void *raw_void_ptr,
|
|
805
|
+
const char *context = "load_as_unique_ptr") {
|
|
806
|
+
if (!have_holder()) {
|
|
807
|
+
return unique_with_deleter<T, D>(nullptr, std::unique_ptr<D>());
|
|
808
|
+
}
|
|
809
|
+
throw_if_uninitialized_or_disowned_holder(typeid(T));
|
|
810
|
+
throw_if_instance_is_currently_owned_by_shared_ptr(tinfo);
|
|
811
|
+
holder().ensure_is_not_disowned(context);
|
|
812
|
+
holder().template ensure_compatible_uqp_del<T, D>(context);
|
|
813
|
+
holder().ensure_use_count_1(context);
|
|
814
|
+
|
|
815
|
+
T *raw_type_ptr = static_cast<T *>(raw_void_ptr);
|
|
816
|
+
|
|
817
|
+
auto *self_life_support = tinfo->get_trampoline_self_life_support(raw_type_ptr);
|
|
818
|
+
// This is enforced indirectly by a static_assert in the class_ implementation:
|
|
819
|
+
assert(!python_instance_is_alias || self_life_support);
|
|
820
|
+
|
|
821
|
+
std::unique_ptr<D> extracted_deleter
|
|
822
|
+
= holder().template extract_deleter<T, D>(context, tinfo->get_memory_guarded_delete);
|
|
823
|
+
|
|
824
|
+
// Critical transfer-of-ownership section. This must stay together.
|
|
825
|
+
if (self_life_support != nullptr) {
|
|
826
|
+
holder().disown(tinfo->get_memory_guarded_delete);
|
|
827
|
+
} else {
|
|
828
|
+
holder().release_ownership(tinfo->get_memory_guarded_delete);
|
|
829
|
+
}
|
|
830
|
+
auto result = unique_with_deleter<T, D>(raw_type_ptr, std::move(extracted_deleter));
|
|
831
|
+
if (self_life_support != nullptr) {
|
|
832
|
+
self_life_support->activate_life_support(loaded_v_h);
|
|
833
|
+
} else {
|
|
834
|
+
void *value_void_ptr = loaded_v_h.value_ptr();
|
|
835
|
+
loaded_v_h.value_ptr() = nullptr;
|
|
836
|
+
deregister_instance(loaded_v_h.inst, value_void_ptr, loaded_v_h.type);
|
|
837
|
+
}
|
|
838
|
+
// Critical section end.
|
|
839
|
+
|
|
840
|
+
return result;
|
|
841
|
+
}
|
|
842
|
+
|
|
843
|
+
// This assumes load_as_shared_ptr succeeded(), and the returned shared_ptr is still alive.
|
|
844
|
+
// The returned unique_ptr is meant to never expire (the behavior is undefined otherwise).
|
|
845
|
+
template <typename D>
|
|
846
|
+
std::unique_ptr<T, D> load_as_const_unique_ptr(const type_info *tinfo,
|
|
847
|
+
T *raw_type_ptr,
|
|
848
|
+
const char *context
|
|
849
|
+
= "load_as_const_unique_ptr") {
|
|
850
|
+
if (!have_holder()) {
|
|
851
|
+
return unique_with_deleter<T, D>(nullptr, std::unique_ptr<D>());
|
|
852
|
+
}
|
|
853
|
+
holder().template ensure_compatible_uqp_del<T, D>(context);
|
|
854
|
+
return unique_with_deleter<T, D>(raw_type_ptr,
|
|
855
|
+
std::move(holder().template extract_deleter<T, D>(
|
|
856
|
+
context, tinfo->get_memory_guarded_delete)));
|
|
857
|
+
}
|
|
858
|
+
};
|
|
859
|
+
|
|
860
|
+
PYBIND11_NAMESPACE_END(smart_holder_type_caster_support)
|
|
861
|
+
|
|
862
|
+
class type_caster_generic {
|
|
863
|
+
public:
|
|
864
|
+
PYBIND11_NOINLINE explicit type_caster_generic(const std::type_info &type_info)
|
|
865
|
+
: typeinfo(get_type_info(type_info)), cpptype(&type_info) {}
|
|
866
|
+
|
|
867
|
+
explicit type_caster_generic(const type_info *typeinfo)
|
|
868
|
+
: typeinfo(typeinfo), cpptype(typeinfo ? typeinfo->cpptype : nullptr) {}
|
|
869
|
+
|
|
870
|
+
bool load(handle src, bool convert) { return load_impl<type_caster_generic>(src, convert); }
|
|
871
|
+
|
|
872
|
+
PYBIND11_NOINLINE static handle cast(const void *_src,
|
|
873
|
+
return_value_policy policy,
|
|
874
|
+
handle parent,
|
|
875
|
+
const detail::type_info *tinfo,
|
|
876
|
+
void *(*copy_constructor)(const void *),
|
|
877
|
+
void *(*move_constructor)(const void *),
|
|
878
|
+
const void *existing_holder = nullptr) {
|
|
879
|
+
if (!tinfo) { // no type info: error will be set already
|
|
880
|
+
return handle();
|
|
881
|
+
}
|
|
882
|
+
|
|
883
|
+
void *src = const_cast<void *>(_src);
|
|
884
|
+
if (src == nullptr) {
|
|
885
|
+
return none().release();
|
|
886
|
+
}
|
|
887
|
+
|
|
888
|
+
if (handle registered_inst = find_registered_python_instance(src, tinfo)) {
|
|
889
|
+
return registered_inst;
|
|
890
|
+
}
|
|
891
|
+
|
|
892
|
+
auto inst = reinterpret_steal<object>(make_new_instance(tinfo->type));
|
|
893
|
+
auto *wrapper = reinterpret_cast<instance *>(inst.ptr());
|
|
894
|
+
wrapper->owned = false;
|
|
895
|
+
void *&valueptr = values_and_holders(wrapper).begin()->value_ptr();
|
|
896
|
+
|
|
897
|
+
switch (policy) {
|
|
898
|
+
case return_value_policy::automatic:
|
|
899
|
+
case return_value_policy::take_ownership:
|
|
900
|
+
valueptr = src;
|
|
901
|
+
wrapper->owned = true;
|
|
902
|
+
break;
|
|
903
|
+
|
|
904
|
+
case return_value_policy::automatic_reference:
|
|
905
|
+
case return_value_policy::reference:
|
|
906
|
+
valueptr = src;
|
|
907
|
+
wrapper->owned = false;
|
|
908
|
+
break;
|
|
909
|
+
|
|
910
|
+
case return_value_policy::copy:
|
|
911
|
+
if (copy_constructor) {
|
|
912
|
+
valueptr = copy_constructor(src);
|
|
913
|
+
} else {
|
|
914
|
+
#if defined(PYBIND11_DETAILED_ERROR_MESSAGES)
|
|
915
|
+
std::string type_name(tinfo->cpptype->name());
|
|
916
|
+
detail::clean_type_id(type_name);
|
|
917
|
+
throw cast_error("return_value_policy = copy, but type " + type_name
|
|
918
|
+
+ " is non-copyable!");
|
|
919
|
+
#else
|
|
920
|
+
throw cast_error("return_value_policy = copy, but type is "
|
|
921
|
+
"non-copyable! (#define PYBIND11_DETAILED_ERROR_MESSAGES or "
|
|
922
|
+
"compile in debug mode for details)");
|
|
923
|
+
#endif
|
|
924
|
+
}
|
|
925
|
+
wrapper->owned = true;
|
|
926
|
+
break;
|
|
927
|
+
|
|
928
|
+
case return_value_policy::move:
|
|
929
|
+
if (move_constructor) {
|
|
930
|
+
valueptr = move_constructor(src);
|
|
931
|
+
} else if (copy_constructor) {
|
|
932
|
+
valueptr = copy_constructor(src);
|
|
933
|
+
} else {
|
|
934
|
+
#if defined(PYBIND11_DETAILED_ERROR_MESSAGES)
|
|
935
|
+
std::string type_name(tinfo->cpptype->name());
|
|
936
|
+
detail::clean_type_id(type_name);
|
|
937
|
+
throw cast_error("return_value_policy = move, but type " + type_name
|
|
938
|
+
+ " is neither movable nor copyable!");
|
|
939
|
+
#else
|
|
940
|
+
throw cast_error("return_value_policy = move, but type is neither "
|
|
941
|
+
"movable nor copyable! "
|
|
942
|
+
"(#define PYBIND11_DETAILED_ERROR_MESSAGES or compile in "
|
|
943
|
+
"debug mode for details)");
|
|
944
|
+
#endif
|
|
945
|
+
}
|
|
946
|
+
wrapper->owned = true;
|
|
947
|
+
break;
|
|
948
|
+
|
|
949
|
+
case return_value_policy::reference_internal:
|
|
950
|
+
valueptr = src;
|
|
951
|
+
wrapper->owned = false;
|
|
952
|
+
keep_alive_impl(inst, parent);
|
|
953
|
+
break;
|
|
954
|
+
|
|
955
|
+
default:
|
|
956
|
+
throw cast_error("unhandled return_value_policy: should not happen!");
|
|
957
|
+
}
|
|
958
|
+
|
|
959
|
+
tinfo->init_instance(wrapper, existing_holder);
|
|
960
|
+
|
|
961
|
+
return inst.release();
|
|
962
|
+
}
|
|
963
|
+
|
|
964
|
+
// Base methods for generic caster; there are overridden in copyable_holder_caster
|
|
965
|
+
void load_value(value_and_holder &&v_h) {
|
|
966
|
+
if (typeinfo->holder_enum_v == detail::holder_enum_t::smart_holder) {
|
|
967
|
+
smart_holder_type_caster_support::value_and_holder_helper v_h_helper;
|
|
968
|
+
v_h_helper.loaded_v_h = v_h;
|
|
969
|
+
if (v_h_helper.have_holder()) {
|
|
970
|
+
v_h_helper.throw_if_uninitialized_or_disowned_holder(cpptype->name());
|
|
971
|
+
value = v_h_helper.holder().template as_raw_ptr_unowned<void>();
|
|
972
|
+
return;
|
|
973
|
+
}
|
|
974
|
+
}
|
|
975
|
+
auto *&vptr = v_h.value_ptr();
|
|
976
|
+
// Lazy allocation for unallocated values:
|
|
977
|
+
if (vptr == nullptr) {
|
|
978
|
+
const auto *type = v_h.type ? v_h.type : typeinfo;
|
|
979
|
+
if (type->operator_new) {
|
|
980
|
+
vptr = type->operator_new(type->type_size);
|
|
981
|
+
} else {
|
|
982
|
+
#if defined(__cpp_aligned_new) && (!defined(_MSC_VER) || _MSC_VER >= 1912)
|
|
983
|
+
if (type->type_align > __STDCPP_DEFAULT_NEW_ALIGNMENT__) {
|
|
984
|
+
vptr = ::operator new(type->type_size, std::align_val_t(type->type_align));
|
|
985
|
+
} else {
|
|
986
|
+
vptr = ::operator new(type->type_size);
|
|
987
|
+
}
|
|
988
|
+
#else
|
|
989
|
+
vptr = ::operator new(type->type_size);
|
|
990
|
+
#endif
|
|
991
|
+
}
|
|
992
|
+
}
|
|
993
|
+
value = vptr;
|
|
994
|
+
}
|
|
995
|
+
bool try_implicit_casts(handle src, bool convert) {
|
|
996
|
+
for (const auto &cast : typeinfo->implicit_casts) {
|
|
997
|
+
type_caster_generic sub_caster(*cast.first);
|
|
998
|
+
if (sub_caster.load(src, convert)) {
|
|
999
|
+
value = cast.second(sub_caster.value);
|
|
1000
|
+
return true;
|
|
1001
|
+
}
|
|
1002
|
+
}
|
|
1003
|
+
return false;
|
|
1004
|
+
}
|
|
1005
|
+
bool try_direct_conversions(handle src) {
|
|
1006
|
+
for (auto &converter : *typeinfo->direct_conversions) {
|
|
1007
|
+
if (converter(src.ptr(), value)) {
|
|
1008
|
+
return true;
|
|
1009
|
+
}
|
|
1010
|
+
}
|
|
1011
|
+
return false;
|
|
1012
|
+
}
|
|
1013
|
+
bool try_cpp_conduit(handle src) {
|
|
1014
|
+
value = try_raw_pointer_ephemeral_from_cpp_conduit(src, cpptype);
|
|
1015
|
+
if (value != nullptr) {
|
|
1016
|
+
return true;
|
|
1017
|
+
}
|
|
1018
|
+
return false;
|
|
1019
|
+
}
|
|
1020
|
+
void check_holder_compat() {}
|
|
1021
|
+
|
|
1022
|
+
PYBIND11_NOINLINE static void *local_load(PyObject *src, const type_info *ti) {
|
|
1023
|
+
auto caster = type_caster_generic(ti);
|
|
1024
|
+
if (caster.load(src, false)) {
|
|
1025
|
+
return caster.value;
|
|
1026
|
+
}
|
|
1027
|
+
return nullptr;
|
|
1028
|
+
}
|
|
1029
|
+
|
|
1030
|
+
/// Try to load with foreign typeinfo, if available. Used when there is no
|
|
1031
|
+
/// native typeinfo, or when the native one wasn't able to produce a value.
|
|
1032
|
+
PYBIND11_NOINLINE bool try_load_foreign_module_local(handle src) {
|
|
1033
|
+
constexpr auto *local_key = PYBIND11_MODULE_LOCAL_ID;
|
|
1034
|
+
const auto pytype = type::handle_of(src);
|
|
1035
|
+
if (!hasattr(pytype, local_key)) {
|
|
1036
|
+
return false;
|
|
1037
|
+
}
|
|
1038
|
+
|
|
1039
|
+
type_info *foreign_typeinfo = reinterpret_borrow<capsule>(getattr(pytype, local_key));
|
|
1040
|
+
// Only consider this foreign loader if actually foreign and is a loader of the correct cpp
|
|
1041
|
+
// type
|
|
1042
|
+
if (foreign_typeinfo->module_local_load == &local_load
|
|
1043
|
+
|| (cpptype && !same_type(*cpptype, *foreign_typeinfo->cpptype))) {
|
|
1044
|
+
return false;
|
|
1045
|
+
}
|
|
1046
|
+
|
|
1047
|
+
if (auto *result = foreign_typeinfo->module_local_load(src.ptr(), foreign_typeinfo)) {
|
|
1048
|
+
value = result;
|
|
1049
|
+
return true;
|
|
1050
|
+
}
|
|
1051
|
+
return false;
|
|
1052
|
+
}
|
|
1053
|
+
|
|
1054
|
+
// Implementation of `load`; this takes the type of `this` so that it can dispatch the relevant
|
|
1055
|
+
// bits of code between here and copyable_holder_caster where the two classes need different
|
|
1056
|
+
// logic (without having to resort to virtual inheritance).
|
|
1057
|
+
template <typename ThisT>
|
|
1058
|
+
PYBIND11_NOINLINE bool load_impl(handle src, bool convert) {
|
|
1059
|
+
if (!src) {
|
|
1060
|
+
return false;
|
|
1061
|
+
}
|
|
1062
|
+
if (!typeinfo) {
|
|
1063
|
+
return try_load_foreign_module_local(src);
|
|
1064
|
+
}
|
|
1065
|
+
|
|
1066
|
+
auto &this_ = static_cast<ThisT &>(*this);
|
|
1067
|
+
this_.check_holder_compat();
|
|
1068
|
+
|
|
1069
|
+
PyTypeObject *srctype = Py_TYPE(src.ptr());
|
|
1070
|
+
|
|
1071
|
+
// Case 1: If src is an exact type match for the target type then we can reinterpret_cast
|
|
1072
|
+
// the instance's value pointer to the target type:
|
|
1073
|
+
if (srctype == typeinfo->type) {
|
|
1074
|
+
this_.load_value(reinterpret_cast<instance *>(src.ptr())->get_value_and_holder());
|
|
1075
|
+
return true;
|
|
1076
|
+
}
|
|
1077
|
+
// Case 2: We have a derived class
|
|
1078
|
+
if (PyType_IsSubtype(srctype, typeinfo->type)) {
|
|
1079
|
+
const auto &bases = all_type_info(srctype);
|
|
1080
|
+
bool no_cpp_mi = typeinfo->simple_type;
|
|
1081
|
+
|
|
1082
|
+
// Case 2a: the python type is a Python-inherited derived class that inherits from just
|
|
1083
|
+
// one simple (no MI) pybind11 class, or is an exact match, so the C++ instance is of
|
|
1084
|
+
// the right type and we can use reinterpret_cast.
|
|
1085
|
+
// (This is essentially the same as case 2b, but because not using multiple inheritance
|
|
1086
|
+
// is extremely common, we handle it specially to avoid the loop iterator and type
|
|
1087
|
+
// pointer lookup overhead)
|
|
1088
|
+
if (bases.size() == 1 && (no_cpp_mi || bases.front()->type == typeinfo->type)) {
|
|
1089
|
+
this_.load_value(reinterpret_cast<instance *>(src.ptr())->get_value_and_holder());
|
|
1090
|
+
return true;
|
|
1091
|
+
}
|
|
1092
|
+
// Case 2b: the python type inherits from multiple C++ bases. Check the bases to see
|
|
1093
|
+
// if we can find an exact match (or, for a simple C++ type, an inherited match); if
|
|
1094
|
+
// so, we can safely reinterpret_cast to the relevant pointer.
|
|
1095
|
+
if (bases.size() > 1) {
|
|
1096
|
+
for (auto *base : bases) {
|
|
1097
|
+
if (no_cpp_mi ? PyType_IsSubtype(base->type, typeinfo->type)
|
|
1098
|
+
: base->type == typeinfo->type) {
|
|
1099
|
+
this_.load_value(
|
|
1100
|
+
reinterpret_cast<instance *>(src.ptr())->get_value_and_holder(base));
|
|
1101
|
+
return true;
|
|
1102
|
+
}
|
|
1103
|
+
}
|
|
1104
|
+
}
|
|
1105
|
+
|
|
1106
|
+
// Case 2c: C++ multiple inheritance is involved and we couldn't find an exact type
|
|
1107
|
+
// match in the registered bases, above, so try implicit casting (needed for proper C++
|
|
1108
|
+
// casting when MI is involved).
|
|
1109
|
+
if (this_.try_implicit_casts(src, convert)) {
|
|
1110
|
+
return true;
|
|
1111
|
+
}
|
|
1112
|
+
}
|
|
1113
|
+
|
|
1114
|
+
// Perform an implicit conversion
|
|
1115
|
+
if (convert) {
|
|
1116
|
+
for (const auto &converter : typeinfo->implicit_conversions) {
|
|
1117
|
+
auto temp = reinterpret_steal<object>(converter(src.ptr(), typeinfo->type));
|
|
1118
|
+
if (load_impl<ThisT>(temp, false)) {
|
|
1119
|
+
loader_life_support::add_patient(temp);
|
|
1120
|
+
return true;
|
|
1121
|
+
}
|
|
1122
|
+
}
|
|
1123
|
+
if (this_.try_direct_conversions(src)) {
|
|
1124
|
+
return true;
|
|
1125
|
+
}
|
|
1126
|
+
}
|
|
1127
|
+
|
|
1128
|
+
// Failed to match local typeinfo. Try again with global.
|
|
1129
|
+
if (typeinfo->module_local) {
|
|
1130
|
+
if (auto *gtype = get_global_type_info(*typeinfo->cpptype)) {
|
|
1131
|
+
typeinfo = gtype;
|
|
1132
|
+
return load(src, false);
|
|
1133
|
+
}
|
|
1134
|
+
}
|
|
1135
|
+
|
|
1136
|
+
// Global typeinfo has precedence over foreign module_local
|
|
1137
|
+
if (try_load_foreign_module_local(src)) {
|
|
1138
|
+
return true;
|
|
1139
|
+
}
|
|
1140
|
+
|
|
1141
|
+
// Custom converters didn't take None, now we convert None to nullptr.
|
|
1142
|
+
if (src.is_none()) {
|
|
1143
|
+
// Defer accepting None to other overloads (if we aren't in convert mode):
|
|
1144
|
+
if (!convert) {
|
|
1145
|
+
return false;
|
|
1146
|
+
}
|
|
1147
|
+
value = nullptr;
|
|
1148
|
+
return true;
|
|
1149
|
+
}
|
|
1150
|
+
|
|
1151
|
+
if (convert && cpptype && this_.try_cpp_conduit(src)) {
|
|
1152
|
+
return true;
|
|
1153
|
+
}
|
|
1154
|
+
|
|
1155
|
+
return false;
|
|
1156
|
+
}
|
|
1157
|
+
|
|
1158
|
+
// Called to do type lookup and wrap the pointer and type in a pair when a dynamic_cast
|
|
1159
|
+
// isn't needed or can't be used. If the type is unknown, sets the error and returns a pair
|
|
1160
|
+
// with .second = nullptr. (p.first = nullptr is not an error: it becomes None).
|
|
1161
|
+
PYBIND11_NOINLINE static std::pair<const void *, const type_info *>
|
|
1162
|
+
src_and_type(const void *src,
|
|
1163
|
+
const std::type_info &cast_type,
|
|
1164
|
+
const std::type_info *rtti_type = nullptr) {
|
|
1165
|
+
if (auto *tpi = get_type_info(cast_type)) {
|
|
1166
|
+
return {src, const_cast<const type_info *>(tpi)};
|
|
1167
|
+
}
|
|
1168
|
+
|
|
1169
|
+
// Not found, set error:
|
|
1170
|
+
std::string tname = rtti_type ? rtti_type->name() : cast_type.name();
|
|
1171
|
+
detail::clean_type_id(tname);
|
|
1172
|
+
std::string msg = "Unregistered type : " + tname;
|
|
1173
|
+
set_error(PyExc_TypeError, msg.c_str());
|
|
1174
|
+
return {nullptr, nullptr};
|
|
1175
|
+
}
|
|
1176
|
+
|
|
1177
|
+
const type_info *typeinfo = nullptr;
|
|
1178
|
+
const std::type_info *cpptype = nullptr;
|
|
1179
|
+
void *value = nullptr;
|
|
1180
|
+
};
|
|
1181
|
+
|
|
1182
|
+
inline object cpp_conduit_method(handle self,
|
|
1183
|
+
const bytes &pybind11_platform_abi_id,
|
|
1184
|
+
const capsule &cpp_type_info_capsule,
|
|
1185
|
+
const bytes &pointer_kind) {
|
|
1186
|
+
#ifdef PYBIND11_HAS_STRING_VIEW
|
|
1187
|
+
using cpp_str = std::string_view;
|
|
1188
|
+
#else
|
|
1189
|
+
using cpp_str = std::string;
|
|
1190
|
+
#endif
|
|
1191
|
+
if (cpp_str(pybind11_platform_abi_id) != PYBIND11_PLATFORM_ABI_ID) {
|
|
1192
|
+
return none();
|
|
1193
|
+
}
|
|
1194
|
+
if (std::strcmp(cpp_type_info_capsule.name(), typeid(std::type_info).name()) != 0) {
|
|
1195
|
+
return none();
|
|
1196
|
+
}
|
|
1197
|
+
if (cpp_str(pointer_kind) != "raw_pointer_ephemeral") {
|
|
1198
|
+
throw std::runtime_error("Invalid pointer_kind: \"" + std::string(pointer_kind) + "\"");
|
|
1199
|
+
}
|
|
1200
|
+
const auto *cpp_type_info = cpp_type_info_capsule.get_pointer<const std::type_info>();
|
|
1201
|
+
type_caster_generic caster(*cpp_type_info);
|
|
1202
|
+
if (!caster.load(self, false)) {
|
|
1203
|
+
return none();
|
|
1204
|
+
}
|
|
1205
|
+
return capsule(caster.value, cpp_type_info->name());
|
|
1206
|
+
}
|
|
1207
|
+
|
|
1208
|
+
/**
|
|
1209
|
+
* Determine suitable casting operator for pointer-or-lvalue-casting type casters. The type caster
|
|
1210
|
+
* needs to provide `operator T*()` and `operator T&()` operators.
|
|
1211
|
+
*
|
|
1212
|
+
* If the type supports moving the value away via an `operator T&&() &&` method, it should use
|
|
1213
|
+
* `movable_cast_op_type` instead.
|
|
1214
|
+
*/
|
|
1215
|
+
template <typename T>
|
|
1216
|
+
using cast_op_type = conditional_t<std::is_pointer<remove_reference_t<T>>::value,
|
|
1217
|
+
typename std::add_pointer<intrinsic_t<T>>::type,
|
|
1218
|
+
typename std::add_lvalue_reference<intrinsic_t<T>>::type>;
|
|
1219
|
+
|
|
1220
|
+
/**
|
|
1221
|
+
* Determine suitable casting operator for a type caster with a movable value. Such a type caster
|
|
1222
|
+
* needs to provide `operator T*()`, `operator T&()`, and `operator T&&() &&`. The latter will be
|
|
1223
|
+
* called in appropriate contexts where the value can be moved rather than copied.
|
|
1224
|
+
*
|
|
1225
|
+
* These operator are automatically provided when using the PYBIND11_TYPE_CASTER macro.
|
|
1226
|
+
*/
|
|
1227
|
+
template <typename T>
|
|
1228
|
+
using movable_cast_op_type
|
|
1229
|
+
= conditional_t<std::is_pointer<typename std::remove_reference<T>::type>::value,
|
|
1230
|
+
typename std::add_pointer<intrinsic_t<T>>::type,
|
|
1231
|
+
conditional_t<std::is_rvalue_reference<T>::value,
|
|
1232
|
+
typename std::add_rvalue_reference<intrinsic_t<T>>::type,
|
|
1233
|
+
typename std::add_lvalue_reference<intrinsic_t<T>>::type>>;
|
|
1234
|
+
|
|
1235
|
+
// Does the container have a mapped type and is it recursive?
|
|
1236
|
+
// Implemented by specializations below.
|
|
1237
|
+
template <typename Container, typename SFINAE = void>
|
|
1238
|
+
struct container_mapped_type_traits {
|
|
1239
|
+
static constexpr bool has_mapped_type = false;
|
|
1240
|
+
static constexpr bool has_recursive_mapped_type = false;
|
|
1241
|
+
};
|
|
1242
|
+
|
|
1243
|
+
template <typename Container>
|
|
1244
|
+
struct container_mapped_type_traits<
|
|
1245
|
+
Container,
|
|
1246
|
+
typename std::enable_if<
|
|
1247
|
+
std::is_same<typename Container::mapped_type, Container>::value>::type> {
|
|
1248
|
+
static constexpr bool has_mapped_type = true;
|
|
1249
|
+
static constexpr bool has_recursive_mapped_type = true;
|
|
1250
|
+
};
|
|
1251
|
+
|
|
1252
|
+
template <typename Container>
|
|
1253
|
+
struct container_mapped_type_traits<
|
|
1254
|
+
Container,
|
|
1255
|
+
typename std::enable_if<
|
|
1256
|
+
negation<std::is_same<typename Container::mapped_type, Container>>::value>::type> {
|
|
1257
|
+
static constexpr bool has_mapped_type = true;
|
|
1258
|
+
static constexpr bool has_recursive_mapped_type = false;
|
|
1259
|
+
};
|
|
1260
|
+
|
|
1261
|
+
// Does the container have a value type and is it recursive?
|
|
1262
|
+
// Implemented by specializations below.
|
|
1263
|
+
template <typename Container, typename SFINAE = void>
|
|
1264
|
+
struct container_value_type_traits : std::false_type {
|
|
1265
|
+
static constexpr bool has_value_type = false;
|
|
1266
|
+
static constexpr bool has_recursive_value_type = false;
|
|
1267
|
+
};
|
|
1268
|
+
|
|
1269
|
+
template <typename Container>
|
|
1270
|
+
struct container_value_type_traits<
|
|
1271
|
+
Container,
|
|
1272
|
+
typename std::enable_if<
|
|
1273
|
+
std::is_same<typename Container::value_type, Container>::value>::type> {
|
|
1274
|
+
static constexpr bool has_value_type = true;
|
|
1275
|
+
static constexpr bool has_recursive_value_type = true;
|
|
1276
|
+
};
|
|
1277
|
+
|
|
1278
|
+
template <typename Container>
|
|
1279
|
+
struct container_value_type_traits<
|
|
1280
|
+
Container,
|
|
1281
|
+
typename std::enable_if<
|
|
1282
|
+
negation<std::is_same<typename Container::value_type, Container>>::value>::type> {
|
|
1283
|
+
static constexpr bool has_value_type = true;
|
|
1284
|
+
static constexpr bool has_recursive_value_type = false;
|
|
1285
|
+
};
|
|
1286
|
+
|
|
1287
|
+
/*
|
|
1288
|
+
* Tag to be used for representing the bottom of recursively defined types.
|
|
1289
|
+
* Define this tag so we don't have to use void.
|
|
1290
|
+
*/
|
|
1291
|
+
struct recursive_bottom {};
|
|
1292
|
+
|
|
1293
|
+
/*
|
|
1294
|
+
* Implementation detail of `recursive_container_traits` below.
|
|
1295
|
+
* `T` is the `value_type` of the container, which might need to be modified to
|
|
1296
|
+
* avoid recursive types and const types.
|
|
1297
|
+
*/
|
|
1298
|
+
template <typename T, bool is_this_a_map>
|
|
1299
|
+
struct impl_type_to_check_recursively {
|
|
1300
|
+
/*
|
|
1301
|
+
* If the container is recursive, then no further recursion should be done.
|
|
1302
|
+
*/
|
|
1303
|
+
using if_recursive = recursive_bottom;
|
|
1304
|
+
/*
|
|
1305
|
+
* Otherwise yield `T` unchanged.
|
|
1306
|
+
*/
|
|
1307
|
+
using if_not_recursive = T;
|
|
1308
|
+
};
|
|
1309
|
+
|
|
1310
|
+
/*
|
|
1311
|
+
* For pairs - only as value type of a map -, the first type should remove the `const`.
|
|
1312
|
+
* Also, if the map is recursive, then the recursive checking should consider
|
|
1313
|
+
* the first type only.
|
|
1314
|
+
*/
|
|
1315
|
+
template <typename A, typename B>
|
|
1316
|
+
struct impl_type_to_check_recursively<std::pair<A, B>, /* is_this_a_map = */ true> {
|
|
1317
|
+
using if_recursive = typename std::remove_const<A>::type;
|
|
1318
|
+
using if_not_recursive = std::pair<typename std::remove_const<A>::type, B>;
|
|
1319
|
+
};
|
|
1320
|
+
|
|
1321
|
+
/*
|
|
1322
|
+
* Implementation of `recursive_container_traits` below.
|
|
1323
|
+
*/
|
|
1324
|
+
template <typename Container, typename SFINAE = void>
|
|
1325
|
+
struct impl_recursive_container_traits {
|
|
1326
|
+
using type_to_check_recursively = recursive_bottom;
|
|
1327
|
+
};
|
|
1328
|
+
|
|
1329
|
+
template <typename Container>
|
|
1330
|
+
struct impl_recursive_container_traits<
|
|
1331
|
+
Container,
|
|
1332
|
+
typename std::enable_if<container_value_type_traits<Container>::has_value_type>::type> {
|
|
1333
|
+
static constexpr bool is_recursive
|
|
1334
|
+
= container_mapped_type_traits<Container>::has_recursive_mapped_type
|
|
1335
|
+
|| container_value_type_traits<Container>::has_recursive_value_type;
|
|
1336
|
+
/*
|
|
1337
|
+
* This member dictates which type Pybind11 should check recursively in traits
|
|
1338
|
+
* such as `is_move_constructible`, `is_copy_constructible`, `is_move_assignable`, ...
|
|
1339
|
+
* Direct access to `value_type` should be avoided:
|
|
1340
|
+
* 1. `value_type` might recursively contain the type again
|
|
1341
|
+
* 2. `value_type` of STL map types is `std::pair<A const, B>`, the `const`
|
|
1342
|
+
* should be removed.
|
|
1343
|
+
*
|
|
1344
|
+
*/
|
|
1345
|
+
using type_to_check_recursively = typename std::conditional<
|
|
1346
|
+
is_recursive,
|
|
1347
|
+
typename impl_type_to_check_recursively<
|
|
1348
|
+
typename Container::value_type,
|
|
1349
|
+
container_mapped_type_traits<Container>::has_mapped_type>::if_recursive,
|
|
1350
|
+
typename impl_type_to_check_recursively<
|
|
1351
|
+
typename Container::value_type,
|
|
1352
|
+
container_mapped_type_traits<Container>::has_mapped_type>::if_not_recursive>::type;
|
|
1353
|
+
};
|
|
1354
|
+
|
|
1355
|
+
/*
|
|
1356
|
+
* This trait defines the `type_to_check_recursively` which is needed to properly
|
|
1357
|
+
* handle recursively defined traits such as `is_move_constructible` without going
|
|
1358
|
+
* into an infinite recursion.
|
|
1359
|
+
* Should be used instead of directly accessing the `value_type`.
|
|
1360
|
+
* It cancels the recursion by returning the `recursive_bottom` tag.
|
|
1361
|
+
*
|
|
1362
|
+
* The default definition of `type_to_check_recursively` is as follows:
|
|
1363
|
+
*
|
|
1364
|
+
* 1. By default, it is `recursive_bottom`, so that the recursion is canceled.
|
|
1365
|
+
* 2. If the type is non-recursive and defines a `value_type`, then the `value_type` is used.
|
|
1366
|
+
* If the `value_type` is a pair and a `mapped_type` is defined,
|
|
1367
|
+
* then the `const` is removed from the first type.
|
|
1368
|
+
* 3. If the type is recursive and `value_type` is not a pair, then `recursive_bottom` is returned.
|
|
1369
|
+
* 4. If the type is recursive and `value_type` is a pair and a `mapped_type` is defined,
|
|
1370
|
+
* then `const` is removed from the first type and the first type is returned.
|
|
1371
|
+
*
|
|
1372
|
+
* This behavior can be extended by the user as seen in test_stl_binders.cpp.
|
|
1373
|
+
*
|
|
1374
|
+
* This struct is exactly the same as impl_recursive_container_traits.
|
|
1375
|
+
* The duplication achieves that user-defined specializations don't compete
|
|
1376
|
+
* with internal specializations, but take precedence.
|
|
1377
|
+
*/
|
|
1378
|
+
template <typename Container, typename SFINAE = void>
|
|
1379
|
+
struct recursive_container_traits : impl_recursive_container_traits<Container> {};
|
|
1380
|
+
|
|
1381
|
+
template <typename T>
|
|
1382
|
+
struct is_move_constructible
|
|
1383
|
+
: all_of<std::is_move_constructible<T>,
|
|
1384
|
+
is_move_constructible<
|
|
1385
|
+
typename recursive_container_traits<T>::type_to_check_recursively>> {};
|
|
1386
|
+
|
|
1387
|
+
template <>
|
|
1388
|
+
struct is_move_constructible<recursive_bottom> : std::true_type {};
|
|
1389
|
+
|
|
1390
|
+
// Likewise for std::pair
|
|
1391
|
+
// (after C++17 it is mandatory that the move constructor not exist when the two types aren't
|
|
1392
|
+
// themselves move constructible, but this can not be relied upon when T1 or T2 are themselves
|
|
1393
|
+
// containers).
|
|
1394
|
+
template <typename T1, typename T2>
|
|
1395
|
+
struct is_move_constructible<std::pair<T1, T2>>
|
|
1396
|
+
: all_of<is_move_constructible<T1>, is_move_constructible<T2>> {};
|
|
1397
|
+
|
|
1398
|
+
// std::is_copy_constructible isn't quite enough: it lets std::vector<T> (and similar) through when
|
|
1399
|
+
// T is non-copyable, but code containing such a copy constructor fails to actually compile.
|
|
1400
|
+
template <typename T>
|
|
1401
|
+
struct is_copy_constructible
|
|
1402
|
+
: all_of<std::is_copy_constructible<T>,
|
|
1403
|
+
is_copy_constructible<
|
|
1404
|
+
typename recursive_container_traits<T>::type_to_check_recursively>> {};
|
|
1405
|
+
|
|
1406
|
+
template <>
|
|
1407
|
+
struct is_copy_constructible<recursive_bottom> : std::true_type {};
|
|
1408
|
+
|
|
1409
|
+
// Likewise for std::pair
|
|
1410
|
+
// (after C++17 it is mandatory that the copy constructor not exist when the two types aren't
|
|
1411
|
+
// themselves copy constructible, but this can not be relied upon when T1 or T2 are themselves
|
|
1412
|
+
// containers).
|
|
1413
|
+
template <typename T1, typename T2>
|
|
1414
|
+
struct is_copy_constructible<std::pair<T1, T2>>
|
|
1415
|
+
: all_of<is_copy_constructible<T1>, is_copy_constructible<T2>> {};
|
|
1416
|
+
|
|
1417
|
+
// The same problems arise with std::is_copy_assignable, so we use the same workaround.
|
|
1418
|
+
template <typename T>
|
|
1419
|
+
struct is_copy_assignable
|
|
1420
|
+
: all_of<
|
|
1421
|
+
std::is_copy_assignable<T>,
|
|
1422
|
+
is_copy_assignable<typename recursive_container_traits<T>::type_to_check_recursively>> {
|
|
1423
|
+
};
|
|
1424
|
+
|
|
1425
|
+
template <>
|
|
1426
|
+
struct is_copy_assignable<recursive_bottom> : std::true_type {};
|
|
1427
|
+
|
|
1428
|
+
template <typename T1, typename T2>
|
|
1429
|
+
struct is_copy_assignable<std::pair<T1, T2>>
|
|
1430
|
+
: all_of<is_copy_assignable<T1>, is_copy_assignable<T2>> {};
|
|
1431
|
+
|
|
1432
|
+
PYBIND11_NAMESPACE_END(detail)
|
|
1433
|
+
|
|
1434
|
+
// polymorphic_type_hook<itype>::get(src, tinfo) determines whether the object pointed
|
|
1435
|
+
// to by `src` actually is an instance of some class derived from `itype`.
|
|
1436
|
+
// If so, it sets `tinfo` to point to the std::type_info representing that derived
|
|
1437
|
+
// type, and returns a pointer to the start of the most-derived object of that type
|
|
1438
|
+
// (in which `src` is a subobject; this will be the same address as `src` in most
|
|
1439
|
+
// single inheritance cases). If not, or if `src` is nullptr, it simply returns `src`
|
|
1440
|
+
// and leaves `tinfo` at its default value of nullptr.
|
|
1441
|
+
//
|
|
1442
|
+
// The default polymorphic_type_hook just returns src. A specialization for polymorphic
|
|
1443
|
+
// types determines the runtime type of the passed object and adjusts the this-pointer
|
|
1444
|
+
// appropriately via dynamic_cast<void*>. This is what enables a C++ Animal* to appear
|
|
1445
|
+
// to Python as a Dog (if Dog inherits from Animal, Animal is polymorphic, Dog is
|
|
1446
|
+
// registered with pybind11, and this Animal is in fact a Dog).
|
|
1447
|
+
//
|
|
1448
|
+
// You may specialize polymorphic_type_hook yourself for types that want to appear
|
|
1449
|
+
// polymorphic to Python but do not use C++ RTTI. (This is a not uncommon pattern
|
|
1450
|
+
// in performance-sensitive applications, used most notably in LLVM.)
|
|
1451
|
+
//
|
|
1452
|
+
// polymorphic_type_hook_base allows users to specialize polymorphic_type_hook with
|
|
1453
|
+
// std::enable_if. User provided specializations will always have higher priority than
|
|
1454
|
+
// the default implementation and specialization provided in polymorphic_type_hook_base.
|
|
1455
|
+
template <typename itype, typename SFINAE = void>
|
|
1456
|
+
struct polymorphic_type_hook_base {
|
|
1457
|
+
static const void *get(const itype *src, const std::type_info *&) { return src; }
|
|
1458
|
+
};
|
|
1459
|
+
template <typename itype>
|
|
1460
|
+
struct polymorphic_type_hook_base<itype, detail::enable_if_t<std::is_polymorphic<itype>::value>> {
|
|
1461
|
+
static const void *get(const itype *src, const std::type_info *&type) {
|
|
1462
|
+
type = src ? &typeid(*src) : nullptr;
|
|
1463
|
+
return dynamic_cast<const void *>(src);
|
|
1464
|
+
}
|
|
1465
|
+
};
|
|
1466
|
+
template <typename itype, typename SFINAE = void>
|
|
1467
|
+
struct polymorphic_type_hook : public polymorphic_type_hook_base<itype> {};
|
|
1468
|
+
|
|
1469
|
+
PYBIND11_NAMESPACE_BEGIN(detail)
|
|
1470
|
+
|
|
1471
|
+
/// Generic type caster for objects stored on the heap
|
|
1472
|
+
template <typename type>
|
|
1473
|
+
class type_caster_base : public type_caster_generic {
|
|
1474
|
+
using itype = intrinsic_t<type>;
|
|
1475
|
+
|
|
1476
|
+
public:
|
|
1477
|
+
static constexpr auto name = const_name<type>();
|
|
1478
|
+
|
|
1479
|
+
type_caster_base() : type_caster_base(typeid(type)) {}
|
|
1480
|
+
explicit type_caster_base(const std::type_info &info) : type_caster_generic(info) {}
|
|
1481
|
+
|
|
1482
|
+
static handle cast(const itype &src, return_value_policy policy, handle parent) {
|
|
1483
|
+
if (policy == return_value_policy::automatic
|
|
1484
|
+
|| policy == return_value_policy::automatic_reference) {
|
|
1485
|
+
policy = return_value_policy::copy;
|
|
1486
|
+
}
|
|
1487
|
+
return cast(std::addressof(src), policy, parent);
|
|
1488
|
+
}
|
|
1489
|
+
|
|
1490
|
+
static handle cast(itype &&src, return_value_policy, handle parent) {
|
|
1491
|
+
return cast(std::addressof(src), return_value_policy::move, parent);
|
|
1492
|
+
}
|
|
1493
|
+
|
|
1494
|
+
// Returns a (pointer, type_info) pair taking care of necessary type lookup for a
|
|
1495
|
+
// polymorphic type (using RTTI by default, but can be overridden by specializing
|
|
1496
|
+
// polymorphic_type_hook). If the instance isn't derived, returns the base version.
|
|
1497
|
+
static std::pair<const void *, const type_info *> src_and_type(const itype *src) {
|
|
1498
|
+
const auto &cast_type = typeid(itype);
|
|
1499
|
+
const std::type_info *instance_type = nullptr;
|
|
1500
|
+
const void *vsrc = polymorphic_type_hook<itype>::get(src, instance_type);
|
|
1501
|
+
if (instance_type && !same_type(cast_type, *instance_type)) {
|
|
1502
|
+
// This is a base pointer to a derived type. If the derived type is registered
|
|
1503
|
+
// with pybind11, we want to make the full derived object available.
|
|
1504
|
+
// In the typical case where itype is polymorphic, we get the correct
|
|
1505
|
+
// derived pointer (which may be != base pointer) by a dynamic_cast to
|
|
1506
|
+
// most derived type. If itype is not polymorphic, we won't get here
|
|
1507
|
+
// except via a user-provided specialization of polymorphic_type_hook,
|
|
1508
|
+
// and the user has promised that no this-pointer adjustment is
|
|
1509
|
+
// required in that case, so it's OK to use static_cast.
|
|
1510
|
+
if (const auto *tpi = get_type_info(*instance_type)) {
|
|
1511
|
+
return {vsrc, tpi};
|
|
1512
|
+
}
|
|
1513
|
+
}
|
|
1514
|
+
// Otherwise we have either a nullptr, an `itype` pointer, or an unknown derived pointer,
|
|
1515
|
+
// so don't do a cast
|
|
1516
|
+
return type_caster_generic::src_and_type(src, cast_type, instance_type);
|
|
1517
|
+
}
|
|
1518
|
+
|
|
1519
|
+
static handle cast(const itype *src, return_value_policy policy, handle parent) {
|
|
1520
|
+
auto st = src_and_type(src);
|
|
1521
|
+
return type_caster_generic::cast(st.first,
|
|
1522
|
+
policy,
|
|
1523
|
+
parent,
|
|
1524
|
+
st.second,
|
|
1525
|
+
make_copy_constructor(src),
|
|
1526
|
+
make_move_constructor(src));
|
|
1527
|
+
}
|
|
1528
|
+
|
|
1529
|
+
static handle cast_holder(const itype *src, const void *holder) {
|
|
1530
|
+
auto st = src_and_type(src);
|
|
1531
|
+
return type_caster_generic::cast(st.first,
|
|
1532
|
+
return_value_policy::take_ownership,
|
|
1533
|
+
{},
|
|
1534
|
+
st.second,
|
|
1535
|
+
nullptr,
|
|
1536
|
+
nullptr,
|
|
1537
|
+
holder);
|
|
1538
|
+
}
|
|
1539
|
+
|
|
1540
|
+
template <typename T>
|
|
1541
|
+
using cast_op_type = detail::cast_op_type<T>;
|
|
1542
|
+
|
|
1543
|
+
// NOLINTNEXTLINE(google-explicit-constructor)
|
|
1544
|
+
operator itype *() { return (type *) value; }
|
|
1545
|
+
// NOLINTNEXTLINE(google-explicit-constructor)
|
|
1546
|
+
operator itype &() {
|
|
1547
|
+
if (!value) {
|
|
1548
|
+
throw reference_cast_error();
|
|
1549
|
+
}
|
|
1550
|
+
return *((itype *) value);
|
|
1551
|
+
}
|
|
1552
|
+
|
|
1553
|
+
protected:
|
|
1554
|
+
using Constructor = void *(*) (const void *);
|
|
1555
|
+
|
|
1556
|
+
/* Only enabled when the types are {copy,move}-constructible *and* when the type
|
|
1557
|
+
does not have a private operator new implementation. A comma operator is used in the
|
|
1558
|
+
decltype argument to apply SFINAE to the public copy/move constructors.*/
|
|
1559
|
+
template <typename T, typename = enable_if_t<is_copy_constructible<T>::value>>
|
|
1560
|
+
static auto make_copy_constructor(const T *)
|
|
1561
|
+
-> decltype(new T(std::declval<const T>()), Constructor{}) {
|
|
1562
|
+
return [](const void *arg) -> void * { return new T(*reinterpret_cast<const T *>(arg)); };
|
|
1563
|
+
}
|
|
1564
|
+
|
|
1565
|
+
template <typename T, typename = enable_if_t<is_move_constructible<T>::value>>
|
|
1566
|
+
static auto make_move_constructor(const T *)
|
|
1567
|
+
-> decltype(new T(std::declval<T &&>()), Constructor{}) {
|
|
1568
|
+
return [](const void *arg) -> void * {
|
|
1569
|
+
return new T(std::move(*const_cast<T *>(reinterpret_cast<const T *>(arg))));
|
|
1570
|
+
};
|
|
1571
|
+
}
|
|
1572
|
+
|
|
1573
|
+
static Constructor make_copy_constructor(...) { return nullptr; }
|
|
1574
|
+
static Constructor make_move_constructor(...) { return nullptr; }
|
|
1575
|
+
};
|
|
1576
|
+
|
|
1577
|
+
inline std::string quote_cpp_type_name(const std::string &cpp_type_name) {
|
|
1578
|
+
return cpp_type_name; // No-op for now. See PR #4888
|
|
1579
|
+
}
|
|
1580
|
+
|
|
1581
|
+
PYBIND11_NOINLINE std::string type_info_description(const std::type_info &ti) {
|
|
1582
|
+
if (auto *type_data = get_type_info(ti)) {
|
|
1583
|
+
handle th((PyObject *) type_data->type);
|
|
1584
|
+
return th.attr("__module__").cast<std::string>() + '.'
|
|
1585
|
+
+ th.attr("__qualname__").cast<std::string>();
|
|
1586
|
+
}
|
|
1587
|
+
return quote_cpp_type_name(clean_type_id(ti.name()));
|
|
1588
|
+
}
|
|
1589
|
+
|
|
1590
|
+
PYBIND11_NAMESPACE_END(detail)
|
|
1591
|
+
PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)
|