#include #include #include namespace torch { namespace impl { template struct RAIIContextManager { explicit RAIIContextManager(Args&&... args) : args_(std::forward(args)...) {} void enter() { auto emplace = [&](Args... args) { guard_.emplace(std::forward(args)...); }; std::apply(std::move(emplace), args_); } void exit() { guard_ = c10::nullopt; } private: c10::optional guard_; std::tuple args_; }; // Turns a C++ RAII guard into a Python context manager. // See _ExcludeDispatchKeyGuard in python_dispatch.cpp for example. template void py_context_manager(const py::module& m, const char* name) { using ContextManagerT = RAIIContextManager; py::class_(m, name) .def(py::init()) .def("__enter__", [](ContextManagerT& guard) { guard.enter(); }) .def( "__exit__", [](ContextManagerT& guard, py::object exc_type, py::object exc_value, py::object traceback) { guard.exit(); }); } template struct DeprecatedRAIIContextManager { explicit DeprecatedRAIIContextManager(Args&&... args) { guard_.emplace(std::forward(args)...); } void enter() {} void exit() { guard_ = c10::nullopt; } private: c10::optional guard_; std::tuple args_; }; // Definition: a "Python RAII guard" is an object in Python that acquires // a resource on init and releases the resource on deletion. // // This API turns a C++ RAII guard into an object can be used either as a // Python context manager or as a "Python RAII guard". // // Please prefer `py_context_manager` to this API if you are binding a new // RAII guard into Python because "Python RAII guards" don't work as expected // in Python (Python makes no guarantees about when an object gets deleted) template void py_context_manager_DEPRECATED(const py::module& m, const char* name) { using ContextManagerT = DeprecatedRAIIContextManager; py::class_(m, name) .def(py::init()) .def("__enter__", [](ContextManagerT& guard) { guard.enter(); }) .def( "__exit__", [](ContextManagerT& guard, py::object exc_type, py::object exc_value, py::object traceback) { guard.exit(); }); } } // namespace impl } // namespace torch