From 098eadefe0f4849d762d227c7df27fc6b82abffc Mon Sep 17 00:00:00 2001 From: "Ralf W. Grosse-Kunstleve" Date: Tue, 20 Mar 2001 02:07:39 +0000 Subject: [PATCH] temp file before branching [SVN r9599] --- include/boost/python/cross_module.hpp | 274 ++++++++++++++++++++++++++ src/cross_module.cpp | 77 ++++++++ 2 files changed, 351 insertions(+) create mode 100644 include/boost/python/cross_module.hpp create mode 100644 src/cross_module.cpp diff --git a/include/boost/python/cross_module.hpp b/include/boost/python/cross_module.hpp new file mode 100644 index 00000000..a6c32889 --- /dev/null +++ b/include/boost/python/cross_module.hpp @@ -0,0 +1,274 @@ +#ifndef CROSS_MODULE_HPP +# define CROSS_MODULE_HPP + +# include + +namespace boost { namespace python { + struct import_error : error_already_set {}; + struct export_error : error_already_set {}; +}} + +namespace boost { namespace python { namespace detail { + +// Concept: throw exception if api_major is changed +// show warning on stderr if api_minor is changed +const int export_converters_api_major = 2; +const int export_converters_api_minor = 1; +extern const char* converters_attribute_name; +void* import_converter_object(const std::string& module_name, + const std::string& py_class_name, + const std::string& attribute_name); +void check_export_converters_api(const int importing_major, + const int importing_minor, + const int imported_major, + const int imported_minor); + +}}} + +// forward declaration +namespace boost { namespace python { namespace detail { +template class import_extension_class; +}}} + +BOOST_PYTHON_BEGIN_CONVERSION_NAMESPACE + +//QUESTIONMARK +// This class is a look-alike of class python_extension_class_converters. +// Is there a formal way to ensure that the siblings stay in sync? +template +class python_import_extension_class_converters +{ + public: + + friend python_import_extension_class_converters py_extension_class_converters(boost::python::type) + { + return python_import_extension_class_converters(); + } + + PyObject* to_python(const T& x) const + { + return boost::python::detail::import_extension_class::get_converters()->to_python(x); + } + + friend T* from_python(PyObject* p, boost::python::type) + { + return boost::python::detail::import_extension_class::get_converters()->T_pointer_from_python(p); + } + + // Convert to const T* + friend const T* from_python(PyObject* p, boost::python::type) + { return from_python(p, boost::python::type()); } + + // Convert to const T* const& + friend const T* from_python(PyObject* p, boost::python::type) + { return from_python(p, boost::python::type()); } + + // Convert to T* const& + friend T* from_python(PyObject* p, boost::python::type) + { return from_python(p, boost::python::type()); } + + // Convert to T& + friend T& from_python(PyObject* p, boost::python::type) { + return boost::python::detail::import_extension_class::get_converters()->T_reference_from_python(p); + } + + // Convert to const T& + friend const T& from_python(PyObject* p, boost::python::type) + { return from_python(p, boost::python::type()); } + + // Convert to T + friend const T& from_python(PyObject* p, boost::python::type) + { return from_python(p, boost::python::type()); } + + friend std::auto_ptr& from_python(PyObject* p, boost::python::type&>) { + return boost::python::detail::import_extension_class::get_converters()->auto_ptr_reference_from_python(p); + } + + friend std::auto_ptr& from_python(PyObject* p, boost::python::type >) { + return boost::python::detail::import_extension_class::get_converters()->auto_ptr_value_from_python(p); + } + + friend const std::auto_ptr& from_python(PyObject* p, boost::python::type&>) { + return boost::python::detail::import_extension_class::get_converters()->auto_ptr_value_from_python(p); + } + + friend PyObject* to_python(std::auto_ptr x) { + return boost::python::detail::import_extension_class::get_converters()->to_python(x); + } + + friend boost::shared_ptr& from_python(PyObject* p, boost::python::type&>) { + return boost::python::detail::import_extension_class::get_converters()->shared_ptr_reference_from_python(p); + } + + friend boost::shared_ptr& from_python(PyObject* p, boost::python::type >) { + return boost::python::detail::import_extension_class::get_converters()->shared_ptr_value_from_python(p); + } + + friend const boost::shared_ptr& from_python(PyObject* p, boost::python::type&>) { + return boost::python::detail::import_extension_class::get_converters()->shared_ptr_value_from_python(p); + } + + friend PyObject* to_python(boost::shared_ptr x) { + return boost::python::detail::import_extension_class::get_converters()->to_python(x); + } +}; + +BOOST_PYTHON_END_CONVERSION_NAMESPACE + +namespace boost { namespace python { + +BOOST_PYTHON_IMPORT_CONVERSION(python_import_extension_class_converters); + +// A pointer to this class is exported/imported via the Python API. +// All functions are virtual. This is, what we really export/import +// is essentially just a pointer to a vtbl. +template +struct export_converter_object_base +{ + virtual const int get_api_major() const { + return detail::export_converters_api_major; } + virtual const int get_api_minor() const { + return detail::export_converters_api_minor; } + virtual PyObject* to_python(const T& x) = 0; + virtual PyObject* to_python(std::auto_ptr x) = 0; + virtual PyObject* to_python(boost::shared_ptr x) = 0; + virtual T* T_pointer_from_python(PyObject* obj) = 0; + virtual T& T_reference_from_python(PyObject* obj) = 0; + virtual std::auto_ptr& auto_ptr_reference_from_python(PyObject* obj) = 0; + virtual std::auto_ptr auto_ptr_value_from_python(PyObject* obj) = 0; + virtual boost::shared_ptr& shared_ptr_reference_from_python(PyObject* obj) = 0; + virtual boost::shared_ptr shared_ptr_value_from_python(PyObject* obj) = 0; +}; + +// Converters to be used if T is not copyable. +template +struct export_converter_object_noncopyable : export_converter_object_base +{ + virtual PyObject* to_python(const T& x) { + PyErr_SetString(PyExc_RuntimeError, + "to_python(const T&) converter not exported"); + throw import_error(); + } + virtual PyObject* to_python(std::auto_ptr x) { + return BOOST_PYTHON_CONVERSION::to_python(x); + } + virtual PyObject* to_python(boost::shared_ptr x) { + return BOOST_PYTHON_CONVERSION::to_python(x); + } + virtual T* T_pointer_from_python(PyObject* obj) { + return BOOST_PYTHON_CONVERSION::from_python(obj, boost::python::type()); + } + virtual T& T_reference_from_python(PyObject* obj) { + return BOOST_PYTHON_CONVERSION::from_python(obj, boost::python::type()); + } + virtual std::auto_ptr& auto_ptr_reference_from_python(PyObject* obj) { + return BOOST_PYTHON_CONVERSION::python_extension_class_converters::smart_ptr_reference(obj, boost::python::type >()); + } + virtual std::auto_ptr auto_ptr_value_from_python(PyObject* obj) { + return BOOST_PYTHON_CONVERSION::python_extension_class_converters::smart_ptr_value(obj, boost::python::type >()); + } + virtual boost::shared_ptr& shared_ptr_reference_from_python(PyObject* obj) { + return BOOST_PYTHON_CONVERSION::python_extension_class_converters::smart_ptr_reference(obj, boost::python::type >()); + } + virtual boost::shared_ptr shared_ptr_value_from_python(PyObject* obj) { + return BOOST_PYTHON_CONVERSION::python_extension_class_converters::smart_ptr_value(obj, boost::python::type >()); + } +}; + +// The addditional to_python() converter that can be used if T is copyable. +template +struct export_converter_object : export_converter_object_noncopyable +{ + virtual PyObject* to_python(const T& x) { + BOOST_PYTHON_CONVERSION::python_extension_class_converters cv; + return cv.to_python(x); + } +}; + +namespace detail { + +//QUESTIONMARK +// A stripped-down, modified version of class extension_class. +// Would it make sense to establish a formal relationship +// between the two classes? +template +class import_extension_class + : public python_import_extension_class_converters +{ + public: + inline import_extension_class(const char* module, const char* py_class) { + m_module = module; + m_py_class = py_class; + } + + static boost::python::export_converter_object_base* get_converters(); + + private: + static std::string m_module; + static std::string m_py_class; + static boost::python::export_converter_object_base* imported_converters; +}; + +template std::string import_extension_class::m_module; +template std::string import_extension_class::m_py_class; +template +boost::python::export_converter_object_base* +import_extension_class::imported_converters = 0; + +template +boost::python::export_converter_object_base* +import_extension_class::get_converters() { + if (imported_converters == 0) { + void* cobject + = import_converter_object(m_module, m_py_class, + converters_attribute_name); + imported_converters + = static_cast*>(cobject); + check_export_converters_api( + export_converters_api_major, + export_converters_api_minor, + imported_converters->get_api_major(), + imported_converters->get_api_minor()); + } + return imported_converters; +} + +}}} // namespace boost::python::detail + +namespace boost { namespace python { + +template +void export_converters(class_builder& cb) +{ + static export_converter_object export_cvts; + cb.add( + ref(PyCObject_FromVoidPtr(reinterpret_cast(&export_cvts), NULL)), + detail::converters_attribute_name); +} + +template +void export_converters_noncopyable(class_builder& cb) +{ + static export_converter_object_noncopyable export_cvts; + cb.add( + ref(PyCObject_FromVoidPtr(reinterpret_cast(&export_cvts), NULL)), + detail::converters_attribute_name); +} + +template +class import_converters + : python_import_extension_class_converters +{ + public: + import_converters(const char* module, const char* py_class) + : m_class(new detail::import_extension_class(module, py_class)) + { } + private: + //QUESTIONMARK + //reference > m_class; + boost::shared_ptr > m_class; +}; + +}} // namespace boost::python + +#endif // CROSS_MODULE_HPP diff --git a/src/cross_module.cpp b/src/cross_module.cpp new file mode 100644 index 00000000..c14acfda --- /dev/null +++ b/src/cross_module.cpp @@ -0,0 +1,77 @@ +# include +namespace python = boost::python; +# include // MSVC6.0SP4 does not know std::fprintf +# include // MSVC6.0SP4 does not know std::strcmp + +namespace { + + PyObject* get_module_dict(const char* module_name) + { + python::ref module_obj(PyImport_ImportModule((char*) module_name)); + PyObject* module_dict = PyModule_GetDict(module_obj.get()); + if (module_dict == 0) throw python::import_error(); + return module_dict; + } +} + +namespace boost { namespace python { namespace detail { + +const char* converters_attribute_name = "__converters__"; + +void* import_converter_object(const std::string& module_name, + const std::string& py_class_name, + const std::string& attribute_name) +{ + static std::string err; + PyObject* module_dict = get_module_dict(const_cast(module_name.c_str())); + PyObject* py_class = PyDict_GetItemString(module_dict, const_cast(py_class_name.c_str())); + if (py_class == 0) { + err = std::string("module ") + module_name + " has no attribute " + py_class_name; + PyErr_SetString(PyExc_RuntimeError, const_cast(err.c_str())); + throw python::import_error(); + } + python::ref c_obj(PyObject_GetAttrString(py_class, const_cast(attribute_name.c_str())), ref::null_ok); + if (c_obj.get() == 0) { + err = std::string("object ") + module_name + "." + py_class_name + + " has no attribute " + attribute_name; + PyErr_SetString(PyExc_RuntimeError, const_cast(err.c_str())); + throw python::import_error(); + } + if (! PyCObject_Check(c_obj.get())) { + err = std::string("object ") + module_name + "." + py_class_name + "." + + attribute_name + " is not a PyCObject"; + PyErr_SetString(PyExc_RuntimeError, const_cast(err.c_str())); + throw python::import_error(); + } + return PyCObject_AsVoidPtr(c_obj.get()); +} + +void check_export_converters_api(const int importing_major, + const int importing_minor, + const int imported_major, + const int imported_minor) +{ + if (importing_major != imported_major) { + // Python uses fprintf(stderr, ...) for API warnings. + fprintf(stderr, + "Fatal: export_converters_api mismatch:" + " Importing module = %d.%d" + " Imported module = %d.%d\n", + importing_major, importing_minor, + imported_major, imported_minor); + PyErr_SetString(PyExc_RuntimeError, + "Fatal: export_converters_api mismatch"); + throw import_error(); + } + if (importing_minor != imported_minor) { + // Python uses fprintf(stderr, ...) for API warnings. + fprintf(stderr, + "Warning: export_converters_api mismatch:" + " Importing module = %d.%d" + " Imported module = %d.%d\n", + importing_major, importing_minor, + imported_major, imported_minor); + } +} + +}}} // namespace boost::python::detail