Created
August 25, 2023 17:43
-
-
Save battleguard/a953e703279ebcb3425f611a187f8326 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <iostream> | |
#define PYBIND11_HANDLE_REF_DEBUG | |
#include <pybind11/pybind11.h> | |
#include <pybind11/operators.h> | |
namespace py = pybind11; | |
using namespace pybind11::literals; | |
struct Platform | |
{ | |
Platform() | |
{ | |
static int platformCount = 1; | |
Index = platformCount++; | |
std::cout << "Platform CTOR Idx: " << Index << " Addr: " << this << std::endl; | |
} | |
~Platform() | |
{ | |
std::cout << "Platform DTOR Idx: " << Index << " Addr: " << this << std::endl; | |
Index = 0; | |
} | |
int Index; | |
}; | |
template<typename T> | |
[[nodiscard]] std::unique_ptr<T> RelinquishPythonOwnship(T* aPythonObject, bool aErrorOnFail = true) | |
{ | |
const void* key = reinterpret_cast<const void*>(aPythonObject); | |
const auto instances = pybind11::detail::get_internals().registered_instances.equal_range(key); | |
for (auto it = instances.first; it != instances.second; ++it) | |
{ | |
pybind11::detail::instance* instance = it->second; | |
if(instance->owned || instance->simple_holder_constructed) | |
{ | |
instance->owned = false; | |
instance->simple_holder_constructed = false; | |
return std::unique_ptr<T>(aPythonObject); | |
} | |
} | |
if(aErrorOnFail) | |
{ | |
py::pybind11_fail("Failed to RelinquishPythonOwnship on passed in python object"); | |
} | |
return std::unique_ptr<T>(nullptr); | |
} | |
struct Collection | |
{ | |
Collection() | |
{ | |
static int Counter = 1; | |
Index = Counter++; | |
std::cout << "Collection CTOR Idx: " << Index << " Addr: " << this << std::endl; | |
} | |
~Collection() | |
{ | |
std::cout << "Collection DTOR Idx: " << Index << " Addr: " << this << std::endl; | |
mOwnedPointers.clear(); | |
Index = 0; | |
std::cout << "Collection DTOR done!" << std::endl;; | |
} | |
void AddPlatform(Platform* aPlatform) | |
{ | |
py::print("Adding platform: ", aPlatform->Index); | |
std::unique_ptr<Platform> ownedPtr = RelinquishPythonOwnship(aPlatform); | |
mOwnedPointers.push_back(std::move(ownedPtr)); | |
} | |
Platform& GetPlatformNonOwning() | |
{ | |
return internal; | |
} | |
Platform* GetPlatform() | |
{ | |
return mOwnedPointers.empty() ? nullptr : mOwnedPointers.front().get(); | |
} | |
int Index; | |
Platform internal; | |
std::vector<std::unique_ptr<Platform>> mOwnedPointers; | |
}; | |
PYBIND11_MODULE(pybind11_example, m) | |
{ | |
py::class_<Platform, std::unique_ptr<Platform>> platform(m, "Platform"); | |
platform.def(py::init()); | |
platform.def_readonly("Index", &Platform::Index); | |
py::class_<Collection, std::unique_ptr<Collection>> sim(m, "Collection"); | |
sim.def(py::init()); | |
sim.def_readonly("Index", &Collection::Index); | |
sim.def("AddPlatform", &Collection::AddPlatform); | |
sim.def("GetPlatform", &Collection::GetPlatform, py::return_value_policy::reference); | |
sim.def("GetPlatformNonOwning", &Collection::GetPlatformNonOwning, py::return_value_policy::reference); | |
auto get_info = [](py::handle obj) | |
{ | |
PyObject* py_obj = obj.ptr(); | |
pybind11::detail::instance* instance_ptr = reinterpret_cast<pybind11::detail::instance*>(py_obj); | |
uintptr_t cpp_address = reinterpret_cast<uintptr_t>(obj.cast<void*>()); | |
uintptr_t py_address = reinterpret_cast<uintptr_t>(obj.ptr()); | |
bool owned = instance_ptr->owned; | |
const pybind11::detail::type_info* py_type_info = pybind11::detail::get_type_info(py_obj->ob_type); | |
py::str object_name(py_obj); | |
if (py_type_info) | |
{ | |
object_name = py::str(py_type_info->cpptype->name()); | |
} | |
return std::make_tuple(object_name, obj.ref_count(), cpp_address, py_address, owned); | |
}; | |
auto print_info = [](const std::tuple<py::str, int, uintptr_t, uintptr_t, bool>& aData) -> void | |
{ | |
auto hex = py::module::import("builtins").attr("hex"); | |
py::print("name = ", std::get<0>(aData), | |
" refs = ", std::get<1>(aData), | |
" cpp_addr = ", hex(std::get<2>(aData)), | |
" py_addr = ", hex(std::get<3>(aData)), | |
" owned = ", std::get<4>(aData)); | |
}; | |
m.def("get_object_info", get_info); | |
m.def("print_info", print_info); | |
auto print_all_instances = [=]() | |
{ | |
py::print("Current Pybind11 Registered Instances:"); | |
auto& refs = pybind11::detail::get_internals().registered_instances; | |
for (const auto& [key, value] : refs) | |
{ | |
PyObject* c_obj = _PyObject_CAST(value); | |
py::handle handle = py::handle(c_obj); | |
print_info(get_info(handle)); | |
} | |
}; | |
m.def("print_obj_info", [=](py::handle obj) | |
{ | |
print_info(get_info(obj)); | |
print_all_instances(); | |
}); | |
m.def("print_registered_instances", print_all_instances); | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import pybind11_example | |
def main(): | |
print("main") | |
platforms = pybind11_example.Collection() | |
platform1 = platforms.GetPlatformNonOwning() | |
platform2 = pybind11_example.Platform() | |
platform3 = pybind11_example.Platform() | |
pybind11_example.print_registered_instances() | |
platforms.AddPlatform(platform2) | |
try: | |
platforms.AddPlatform(platform1) | |
except RuntimeError as e: | |
print("Cannot add a non owning platform: ", platform1) | |
print(e) | |
finally: | |
pass | |
platform4 = platforms.GetPlatform() | |
pybind11_example.print_registered_instances() | |
print("end_main") | |
if __name__ == '__main__': | |
main() | |
pybind11_example.print_registered_instances() | |
print("Program Complete") |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
$ "C:/Program Files/Python310/python.exe" c:/working/py11_playground/pybind11_example/main.py | |
main | |
Platform CTOR Idx: 1 Addr: 0000024928AA84A4 | |
Collection CTOR Idx: 1 Addr: 0000024928AA84A0 | |
Platform CTOR Idx: 2 Addr: 0000024928AA31B0 | |
Platform CTOR Idx: 3 Addr: 0000024928AA3110 | |
Current Pybind11 Registered Instances: | |
name = struct Collection refs = 1 cpp_addr = 0x24928aa84a0 py_addr = 0x24929227870 owned = True | |
name = struct Platform refs = 1 cpp_addr = 0x24928aa84a4 py_addr = 0x24929227770 owned = False | |
name = struct Platform refs = 1 cpp_addr = 0x24928aa3110 py_addr = 0x249292357f0 owned = True | |
name = struct Platform refs = 1 cpp_addr = 0x24928aa31b0 py_addr = 0x249292275b0 owned = True | |
Adding platform: 2 | |
Adding platform: 1 | |
Cannot add a non owning platform: <pybind11_example.Platform object at 0x0000024929227770> | |
Failed to RelinquishPythonOwnship on passed in python object | |
Current Pybind11 Registered Instances: | |
name = struct Collection refs = 1 cpp_addr = 0x24928aa84a0 py_addr = 0x24929227870 owned = True | |
name = struct Platform refs = 1 cpp_addr = 0x24928aa84a4 py_addr = 0x24929227770 owned = False | |
name = struct Platform refs = 1 cpp_addr = 0x24928aa3110 py_addr = 0x249292357f0 owned = True | |
name = struct Platform refs = 2 cpp_addr = 0x24928aa31b0 py_addr = 0x249292275b0 owned = False | |
end_main | |
Collection DTOR Idx: 1 Addr: 0000024928AA84A0 | |
Platform DTOR Idx: 2 Addr: 0000024928AA31B0 | |
Collection DTOR done! | |
Platform DTOR Idx: 1 Addr: 0000024928AA84A4 | |
Platform DTOR Idx: 3 Addr: 0000024928AA3110 | |
Current Pybind11 Registered Instances: | |
Program Complete |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment