diff --git a/Jamfile b/Jamfile index 684c21d5..fec34d51 100644 --- a/Jamfile +++ b/Jamfile @@ -15,7 +15,6 @@ PYTHON_PROPERTIES dll bpl : src/converter/from_python.cpp - src/converter/to_python.cpp src/converter/registry.cpp src/converter/type_id.cpp src/object/class.cpp diff --git a/example/rwgk2.cpp b/example/rwgk2.cpp deleted file mode 100644 index 35dce88f..00000000 --- a/example/rwgk2.cpp +++ /dev/null @@ -1,50 +0,0 @@ -#include -#include - -namespace { // Avoid cluttering the global namespace. - - // A friendly class. - class world - { - private: - std::string country; - public: - world(const std::string& country) { this->country = country; } - std::string greet() const { return "Hello from " + country + "!"; } - }; - - // A function taking a world object as an argument. - std::string invite(const world& w) { - return w.greet() + " Please come soon!"; - } -} - -#include - -// Python requires an exported function called init in every -// extension module. This is where we build the module contents. -BOOST_PYTHON_MODULE_INIT(example2) -{ - // Create an object representing this extension module. - py::Module this_module("example2"); - - // Create the Python type object for our extension class. - py::ClassWrapper world_class(this_module, "world"); - - // Add the __init__ function. - world_class.def(py::Constructor()); - // Add a regular member function. - world_class.def(&world::greet, "greet"); - - // Add invite() as a regular function to the module. - this_module.def(invite, "invite"); - - // Even better, invite() can also be made a member of world_class!!! - world_class.def(invite, "invite"); -} - -// Win32 DLL boilerplate -#if defined(_WIN32) -#include -extern "C" BOOL WINAPI DllMain(HINSTANCE, DWORD, LPVOID) { return 1; } -#endif // _WIN32 diff --git a/example/rwgk3.cpp b/example/rwgk3.cpp deleted file mode 100644 index df17b28e..00000000 --- a/example/rwgk3.cpp +++ /dev/null @@ -1,101 +0,0 @@ -#include -#include - -#define rangei(n) for (int i = 0; i < n; i++) - -namespace { // Avoid cluttering the global namespace. - - // A wrapper is used to define additional constructors. - // - struct vector_double_wrapper: std::vector - { - // Tell the compiler how to convert a base class object to - // this wrapper object. - vector_double_wrapper(PyObject*, const std::vector& vd) - : std::vector(vd) {} - - vector_double_wrapper(PyObject* self) - : std::vector() {} - - vector_double_wrapper(PyObject* self, const int n) - : std::vector(n) {} - - vector_double_wrapper(PyObject* self, py::Tuple tuple) - : std::vector(tuple.size()) - { - std::vector::iterator vd = begin(); - rangei(tuple.size()) - vd[i] = from_python(tuple[i].get(), py::Type()); // GCC BUG - } - }; - - double getitem(const std::vector& vd, const std::size_t key) { - return vd[key]; - } - - void setitem(std::vector& vd, const std::size_t key, - const double &d) { - std::vector::iterator vditer = vd.begin(); - vditer[key] = d; - } - - void delitem(std::vector& vd, const std::size_t key) { - std::vector::iterator vditer = vd.begin(); - vd.erase(&vditer[key]); - } - - // Convert vector_double to a regular Python tuple. - // - py::Tuple as_tuple(const std::vector& vd) - { - py::Tuple t(vd.size()); - rangei(vd.size()) t.set_item(i, py::Ptr(py::to_python(vd[i]))); // GCC BUG - return t; - } - - // Function returning a vector_double object to Python. - // - std::vector foo(const int n) - { - std::vector vd(n); - std::vector::iterator vditer = vd.begin(); - rangei(n) vditer[i] = double(i); - return vd; - } - - // Same as foo(), but avoid copying on return. - // - std::auto_ptr > bar(const int n) - { - std::auto_ptr > vdptr(new std::vector(n)); - std::vector::iterator vditer = vdptr->begin(); - rangei(n) vditer[i] = double(10 * i); - return vdptr; - } -} - -BOOST_PYTHON_MODULE_INIT(example3) -{ - py::Module this_module("example3"); - - py::ClassWrapper, vector_double_wrapper> - vector_double(this_module, "vector_double"); - - vector_double.def(py::Constructor<>()); - vector_double.def(py::Constructor()); - vector_double.def(py::Constructor()); - vector_double.def(&std::vector::size, "__len__"); - vector_double.def(getitem, "__getitem__"); - vector_double.def(setitem, "__setitem__"); - vector_double.def(delitem, "__delitem__"); - vector_double.def(as_tuple, "as_tuple"); - - this_module.def(foo, "foo"); - this_module.def(bar, "bar"); -} - -// Win32 DLL boilerplate -#if defined(_WIN32) -#include -extern "C" BOOL WINAPI DllMain(HINSTANCE, DWORD, LPVOID) { return 1; } -#endif // _WIN32 diff --git a/include/boost/python/converter/builtin_to_python_converters.hpp b/include/boost/python/converter/builtin_to_python_converters.hpp index 4e9f89e3..89ad7b86 100644 --- a/include/boost/python/converter/builtin_to_python_converters.hpp +++ b/include/boost/python/converter/builtin_to_python_converters.hpp @@ -8,20 +8,41 @@ # include # include -namespace boost { namespace python { namespace converter { +namespace boost { namespace python { -template struct to_python_lookup; +// Provide specializations of to_python_value +template struct to_python_value; -template -struct to_python_int +namespace detail { - bool convertible() const { return true; } - PyObject* operator()(T x) const { return PyInt_FromLong(long(x)); } -}; + struct builtin_to_python + { + static bool convertible() { return true; } + }; +} -# define BOOST_PYTHON_TO_INT(T) \ - template <> struct to_python_lookup : to_python_int {}; \ - template <> struct to_python_lookup : to_python_int {}; +# define BOOST_PYTHON_TO_PYTHON_BY_VALUE(T, expr) \ + template <> struct to_python_value \ + : detail::builtin_to_python \ + { \ + PyObject* operator()(T const& x) const \ + { \ + return (expr); \ + } \ + }; \ + template <> struct to_python_value \ + : detail::builtin_to_python \ + { \ + PyObject* operator()(T const& x) const \ + { \ + return (expr); \ + } \ + }; + + +# define BOOST_PYTHON_TO_INT(T) \ + BOOST_PYTHON_TO_PYTHON_BY_VALUE(signed T, PyInt_FromLong(x)) \ + BOOST_PYTHON_TO_PYTHON_BY_VALUE(unsigned T, PyInt_FromLong(x)) BOOST_PYTHON_TO_INT(char) BOOST_PYTHON_TO_INT(short) @@ -29,47 +50,13 @@ BOOST_PYTHON_TO_INT(int) BOOST_PYTHON_TO_INT(long) # undef BOOST_TO_PYTHON_INT -template <> -struct to_python_lookup -{ - bool convertible() const { return true; } - PyObject* operator()(char const* x) const { return PyString_FromString(x); } -}; - -template <> -struct to_python_lookup -{ - bool convertible() const { return true; } - PyObject* operator()(std::string const& x) const - { - return PyString_FromString(x.c_str()); - } -}; +BOOST_PYTHON_TO_PYTHON_BY_VALUE(char const*, PyString_FromString(x)) +BOOST_PYTHON_TO_PYTHON_BY_VALUE(std::string, PyString_FromString(x.c_str())) +BOOST_PYTHON_TO_PYTHON_BY_VALUE(float, PyFloat_FromDouble(x)) +BOOST_PYTHON_TO_PYTHON_BY_VALUE(double, PyFloat_FromDouble(x)) +BOOST_PYTHON_TO_PYTHON_BY_VALUE(long double, PyFloat_FromDouble(x)) +BOOST_PYTHON_TO_PYTHON_BY_VALUE(PyObject*, x) -template <> -struct to_python_lookup -{ - bool convertible() const { return true; } - PyObject* operator()(float x) const { return PyFloat_FromDouble(x); } -}; - -template <> -struct to_python_lookup -{ - bool convertible() const { return true; } - PyObject* operator()(double x) const { return PyFloat_FromDouble(x); } -}; - -template <> -struct to_python_lookup -{ - bool convertible() const { return true; } - PyObject* operator()(long double x) const - { - return PyFloat_FromDouble(x); - } -}; - -}}} // namespace boost::python::converter +}} // namespace boost::python::converter #endif // BUILTIN_TO_PYTHON_CONVERTERS_DWA2002129_HPP diff --git a/include/boost/python/converter/from_python.hpp b/include/boost/python/converter/from_python.hpp index 234f61d1..ee16a741 100644 --- a/include/boost/python/converter/from_python.hpp +++ b/include/boost/python/converter/from_python.hpp @@ -11,7 +11,7 @@ # include # include # include -# include +# include # include namespace boost { namespace python { namespace converter { @@ -29,16 +29,21 @@ template struct from_python_lookup; struct BOOST_PYTHON_DECL from_python_converter_base : body { from_python_converter_base(type_id_t, from_python_check); // registers - ~from_python_converter_base(); // unregisters // Must return non-null iff the conversion will be successful. Any // non-null pointer is acceptable, and will be passed on to the // convert() function, so useful data can be stored there. inline void* convertible(PyObject*) const; -// inline type_id_t key() const; + + // Given the head of a from_python converter chain, find the + // converter which can convert p, leaving its intermediate data in + // data. + inline static from_python_converter_base const* + find(from_python_converter_base const*chain, PyObject* p, void*& data); + private: -// type_id_t m_key; from_python_check m_convertible; + from_python_converter_base* m_next; }; @@ -52,17 +57,24 @@ struct from_python_converter : from_python_converter_base from_python_converter(from_python_check, conversion_function, from_python_destructor = 0); T convert(PyObject*, from_python_data&) const; void destroy(from_python_data&) const; + + // Find a converter for converting p to a T. + static from_python_converter const* find(PyObject* p, void*& data); private: // data members conversion_function m_convert; from_python_destructor m_destroy; + + // Keeps the chain of converters which convert from PyObject* to T + static from_python_converter_base*const& chain; }; -// ------------------------------------------------------------------------- +// Initialized to refer to a common place in the registry. +template +from_python_converter_base*const& +from_python_converter::chain = registry::from_python_chain(type_id()); -//struct from_python_base -//{ -//}; +// ------------------------------------------------------------------------- // A class which implements from_python with a registry lookup. template @@ -95,12 +107,21 @@ inline void* from_python_converter_base::convertible(PyObject* o) const return m_convertible(o); } -# if 0 -inline type_id_t from_python_converter_base::key() const +inline from_python_converter_base const* +from_python_converter_base::find( + from_python_converter_base const* chain, PyObject* p, void*& data) { - return m_key; + for (from_python_converter_base const* q = chain; q != 0 ; q = q->m_next) + { + void* d = q->convertible(p); + if (d != 0) + { + data = d; + return q; + } + } + return 0; } -# endif template inline from_python_converter::from_python_converter( @@ -115,6 +136,14 @@ inline from_python_converter::from_python_converter( } +template +inline from_python_converter const* +from_python_converter::find(PyObject* p, void*& data) +{ + return static_cast const*>( + from_python_converter_base::find(chain, p, data)); +} + template inline T from_python_converter::convert(PyObject* src, from_python_data& data) const { @@ -133,7 +162,7 @@ inline void from_python_converter::destroy(from_python_data& data) const template inline from_python_lookup::from_python_lookup(PyObject* src) : m_converter( - registration::get_from_python( + from_python_converter::find( src, m_intermediate_data.stage1)) { } diff --git a/include/boost/python/converter/registration.hpp b/include/boost/python/converter/registration.hpp deleted file mode 100644 index 39223d8a..00000000 --- a/include/boost/python/converter/registration.hpp +++ /dev/null @@ -1,148 +0,0 @@ -// Copyright David Abrahams 2001. Permission to copy, use, -// modify, sell and distribute this software is granted provided this -// copyright notice appears in all copies. This software is provided -// "as is" without express or implied warranty, and with no claim as -// to its suitability for any purpose. -#ifndef REGISTRATION_DWA20011130_HPP -# define REGISTRATION_DWA20011130_HPP -# include -# include -# include -# include -# include -# include -# include -# include -# ifdef BOOST_PYTHON_TRACE -# include -# endif - -namespace boost { namespace python { namespace converter { - -template struct from_python_converter; -template struct target; -template struct source; - -// This class is really sort of a "templated namespace". It manages a -// static data member which refers to the registry entry for T. This -// reference is acquired once to reduce the burden of multiple -// dictionary lookups at runtime. -template -struct registration -{ - public: // member functions - // Return a converter which can convert the given Python object to - // T, or 0 if no such converter exists. Fill in data with - // the result of the converter's check function - static from_python_converter const* get_from_python(PyObject*, void*& data); - - // Return a converter which can convert T to a Python object, or 0 - // if no such converter exists - static to_python_function::type get_to_python(); - - static registry::entry* find_entry(); - private: // helper functions - static registry::entry* entry(); - static registry::entry* known_entry(); - - private: // data members - static registry::entry* m_registry_entry; -}; - -namespace detail -{ - // An MPL BinaryMetaFunction class which initializes the - // registration entry for the target type of its 2nd argument. - struct setup_target_registration - { - template struct apply - { - typedef T type; - static void execute() - { - typedef typename target::type target_t; - registration::find_entry(); - } - }; - }; - - template - struct find_return_value_entry - { - static void execute() { registration::find_entry(); } - }; - - template <> - struct find_return_value_entry - { - static void execute() {} - }; - -# if !defined(BOOST_MSVC) || BOOST_MSVC > 1200 - template <> - struct find_return_value_entry - { - static void execute() {} - }; -# endif -} - -template -void acquire_registrations(Sequence signature) -{ - typedef typename mpl::pop_front::sequence args; - typedef typename mpl::front::type return_type; - - mpl::for_each::execute(); - - typedef typename source::type return_source_type; - detail::find_return_value_entry::execute(); -} - - -// because this is static POD data it will be initialized to zero -template -registry::entry* registration::m_registry_entry; - -template -registry::entry* registration::find_entry() -{ - return m_registry_entry = registry::find(type_id()); -} - -template -inline registry::entry* registration::entry() -{ - if (!m_registry_entry) - find_entry(); - return m_registry_entry; -} - -template -inline registry::entry* registration::known_entry() -{ - assert(m_registry_entry != 0); - return m_registry_entry; -} - -template -from_python_converter const* registration::get_from_python(PyObject* p, void*& data) -{ - return static_cast const*>( - known_entry()->get_from_python(p, data) - ); -} - -template -typename to_python_function::type registration::get_to_python() -{ -# ifdef BOOST_PYTHON_TRACE - std::cout << "retrieving wrapper for " << type_id() << std::endl; -# endif - return reinterpret_cast::type>( - known_entry()->get_to_python()); -} - -}}} // namespace boost::python::converter - -#endif // REGISTRATION_DWA20011130_HPP diff --git a/include/boost/python/converter/registry.hpp b/include/boost/python/converter/registry.hpp index 21f31692..bdb64254 100644 --- a/include/boost/python/converter/registry.hpp +++ b/include/boost/python/converter/registry.hpp @@ -5,72 +5,26 @@ // to its suitability for any purpose. #ifndef REGISTRY_DWA20011127_HPP # define REGISTRY_DWA20011127_HPP -# include # include # include +# include # include -# include -# include -# include namespace boost { namespace python { namespace converter { struct BOOST_PYTHON_DECL from_python_converter_base; -struct BOOST_PYTHON_DECL to_python_converter_base; // This namespace acts as a sort of singleton namespace registry { - // These are the elements stored in the registry - class BOOST_PYTHON_DECL entry - { - public: // member functions - entry(); - ~entry(); - - // Return a converter appropriate for converting the given - // Python object from_python to the C++ type with which this - // converter is associated in the registry, or 0 if no such - // converter exists. - from_python_converter_base const* get_from_python(PyObject*, void*& data) const; - - // Return a conversion function appropriate for converting a C++ - // object whose type this entry is associated with in the - // registry to a Python object, or 0 if no such converter - // exists. This function must be reinterpret_cast to the - // appropriate to_python_function type. - to_python_function_base get_to_python() const; - - // Conversion classes use these functions to register - // themselves. - void insert(from_python_converter_base&); - void remove(from_python_converter_base&); - - void insert(to_python_converter_base&); - void remove(to_python_converter_base&); - - private: // types - typedef std::vector from_python_converters; - - private: // helper functions - from_python_converters::iterator find(from_python_converter_base const&); - - private: // data members - - // The collection of from_python converters for the associated - // C++ type. - from_python_converters m_from_python_converters; - - // The unique to_python converter for the associated C++ type. - to_python_converter_base* m_to_python_converter; - }; - - BOOST_PYTHON_DECL entry* find(type_id_t); + BOOST_PYTHON_DECL to_python_value_function const& + to_python_function(undecorated_type_id_t); - BOOST_PYTHON_DECL void insert(to_python_converter_base& x); - BOOST_PYTHON_DECL void insert(from_python_converter_base& x); - BOOST_PYTHON_DECL void remove(to_python_converter_base& x); - BOOST_PYTHON_DECL void remove(from_python_converter_base& x); + BOOST_PYTHON_DECL void insert(to_python_value_function, undecorated_type_id_t); + + BOOST_PYTHON_DECL from_python_converter_base*& from_python_chain(type_id_t); + + BOOST_PYTHON_DECL PyTypeObject*& class_object(undecorated_type_id_t key); } }}} // namespace boost::python::converter diff --git a/include/boost/python/converter/source.hpp b/include/boost/python/converter/source.hpp deleted file mode 100644 index 9abf245f..00000000 --- a/include/boost/python/converter/source.hpp +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright David Abrahams 2001. Permission to copy, use, -// modify, sell and distribute this software is granted provided this -// copyright notice appears in all copies. This software is provided -// "as is" without express or implied warranty, and with no claim as -// to its suitability for any purpose. -#ifndef SOURCE_DWA20011119_HPP -# define SOURCE_DWA20011119_HPP -# include -# include -# include - -namespace boost { namespace python { namespace converter { - -// source -- -// -// This type generator (see -// ../../../more/generic_programming.html#type_generator) is used -// to select the argument type to use when converting T to a PyObject* - -template -struct source -{ - typedef - typename add_reference< - typename add_const::type - >::type - type; -}; - -}}} // namespace boost::python::converter - -#endif // SOURCE_DWA20011119_HPP diff --git a/include/boost/python/converter/source_holder.hpp b/include/boost/python/converter/source_holder.hpp deleted file mode 100644 index f2c774f9..00000000 --- a/include/boost/python/converter/source_holder.hpp +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright David Abrahams 2001. Permission to copy, use, -// modify, sell and distribute this software is granted provided this -// copyright notice appears in all copies. This software is provided -// "as is" without express or implied warranty, and with no claim as -// to its suitability for any purpose. -#ifndef SOURCE_HOLDER_DWA20011215_HPP -# define SOURCE_HOLDER_DWA20011215_HPP - -namespace boost { namespace python { namespace converter { - -struct source_holder_base -{ -}; - -template -struct source_holder : source_holder_base -{ - source_holder(T x) : value(x) {} - T value; -}; - -}}} // namespace boost::python::converter - -#endif // SOURCE_HOLDER_DWA20011215_HPP diff --git a/include/boost/python/converter/to_python.hpp b/include/boost/python/converter/to_python.hpp deleted file mode 100644 index a1d6c28b..00000000 --- a/include/boost/python/converter/to_python.hpp +++ /dev/null @@ -1,116 +0,0 @@ -// Copyright David Abrahams 2002. Permission to copy, use, -// modify, sell and distribute this software is granted provided this -// copyright notice appears in all copies. This software is provided -// "as is" without express or implied warranty, and with no claim as -// to its suitability for any purpose. -#ifndef TO_PYTHON_DWA2002127_HPP -# define TO_PYTHON_DWA2002127_HPP - -# include -# include -# include -# include -# include -# include - -namespace boost { namespace python { namespace converter { - -template struct to_python_lookup; - -struct BOOST_PYTHON_DECL to_python_converter_base : body -{ - to_python_converter_base(type_id_t, to_python_function_base); // registers - ~to_python_converter_base(); // unregisters - -// inline type_id_t key() const; - inline to_python_function_base converter() const; - private: -// type_id_t m_key; - to_python_function_base m_convert; -}; - -template -struct to_python_converter : to_python_converter_base -{ - public: // types - typedef typename to_python_function::type converter_t; - - public: // member functions - to_python_converter(converter_t); - converter_t converter() const; - - private: // data members - converter_t m_convert; -}; - -// ------------------------------------------------------------------------- - -//struct to_python_base {}; - -template -struct to_python_lookup //: to_python_base -{ - public: // member functions - to_python_lookup(); - bool convertible() const; - PyObject* operator()(T) const; - private: - typename to_python_function::type m_convert; -}; - -// -// implementations -// -# if 0 -inline type_id_t -to_python_converter_base::key() const -{ - return m_key; -} -# endif - -inline to_python_function_base -to_python_converter_base::converter() const -{ - return m_convert; -} - -template -to_python_converter::to_python_converter(converter_t convert) - : to_python_converter_base( - type_id(), reinterpret_cast(convert)) -{ -} - -template -inline typename to_python_function::type -to_python_converter::converter() const -{ - return reinterpret_cast( - this->to_python_converter_base::converter()); -} - -template -inline to_python_lookup::to_python_lookup() - : m_convert( - registration::get_to_python()) -{ -} - -template -inline bool -to_python_lookup::convertible() const -{ - return m_convert != 0; -} - -template -inline PyObject* -to_python_lookup::operator()(T x) const -{ - return m_convert ? m_convert(x) : 0; -} - -}}} // namespace boost::python::converter - -#endif // TO_PYTHON_DWA2002127_HPP diff --git a/include/boost/python/converter/to_python_function.hpp b/include/boost/python/converter/to_python_function.hpp index 9d408749..a438ce0c 100644 --- a/include/boost/python/converter/to_python_function.hpp +++ b/include/boost/python/converter/to_python_function.hpp @@ -7,15 +7,24 @@ # define TO_PYTHON_FUNCTION_DWA2002128_HPP # include +# include namespace boost { namespace python { namespace converter { -typedef PyObject* (*to_python_function_base)(void); +// The type of stored function pointers which actually do conversion +// by-value. The void* points to the object to be converted, and +// type-safety is preserved through runtime registration. +typedef PyObject* (*to_python_value_function)(void const*); -template -struct to_python_function +// Given a typesafe to_python conversion function, produces a +// to_python_value_function which can be registered in the usual way. +template +struct as_to_python_value_function { - typedef PyObject*(*type)(T); + static PyObject* convert(void const* x) + { + return ToPython::convert(*(T const*)x); + } }; }}} // namespace boost::python::converter diff --git a/include/boost/python/converter/type_id.hpp b/include/boost/python/converter/type_id.hpp index e5068604..015e55e9 100644 --- a/include/boost/python/converter/type_id.hpp +++ b/include/boost/python/converter/type_id.hpp @@ -7,8 +7,12 @@ # define TYPE_ID_DWA20011127_HPP # include # include +# include +# include +# include # include # include +# include # include # include # include @@ -16,13 +20,6 @@ namespace boost { namespace python { namespace converter { -// a portable mechanism for identifying types at runtime across modules. - -namespace detail -{ - template class dummy; -} - // for this compiler at least, cross-shared-library type_info // comparisons don't work, so use typeid(x).name() instead. It's not // yet clear what the best default strategy is. @@ -61,7 +58,7 @@ struct type_id_t : totally_ordered { enum decoration { const_ = 0x1, volatile_ = 0x2, reference = 0x4 }; - type_id_t(undecorated_type_id_t, decoration decoration); + type_id_t(undecorated_type_id_t, decoration = decoration()); bool operator<(type_id_t const& rhs) const; bool operator==(type_id_t const& rhs) const; @@ -78,13 +75,19 @@ struct type_id_t : totally_ordered }; template -inline undecorated_type_id_t undecorated_type_id(detail::dummy* = 0) +inline undecorated_type_id_t undecorated_type_id(boost::type* = 0) { - return undecorated_type_id_t(typeid(T)); + return undecorated_type_id_t( +# if (!defined(BOOST_MSVC) || BOOST_MSVC > 1300) && (!defined(BOOST_INTEL_CXX_VERSION) || BOOST_INTEL_CXX_VERSION > 600) + typeid(T) +# else // strip the decoration which msvc and Intel mistakenly leave in + python::detail::msvc_typeid() +# endif + ); } template -inline type_id_t type_id(detail::dummy* = 0) +inline type_id_t type_id(boost::type* = 0) { return type_id_t( undecorated_type_id() diff --git a/include/boost/python/converter/wrapper_base.hpp b/include/boost/python/converter/wrapper_base.hpp deleted file mode 100644 index 585959ae..00000000 --- a/include/boost/python/converter/wrapper_base.hpp +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright David Abrahams 2002. Permission to copy, use, -// modify, sell and distribute this software is granted provided this -// copyright notice appears in all copies. This software is provided -// "as is" without express or implied warranty, and with no claim as -// to its suitability for any purpose. -#ifndef WRAPPER_BASE_DWA2002110_HPP -# define WRAPPER_BASE_DWA2002110_HPP -# include -# include - -namespace boost { namespace python { namespace converter { - -struct source_holder_base; -struct wrap_base; -template struct wrap_more_; - -struct BOOST_PYTHON_DECL wrapper_base : body -{ - public: - wrapper_base(type_id_t); // registers - ~wrapper_base(); // unregisters - - virtual PyObject* do_conversion(wrap_base const&, source_holder_base const&) const = 0; -}; - -}}} // namespace boost::python::converter - -#endif // WRAPPER_BASE_DWA2002110_HPP diff --git a/include/boost/python/copy_const_reference.hpp b/include/boost/python/copy_const_reference.hpp index 57c45fd4..b2fdd61f 100644 --- a/include/boost/python/copy_const_reference.hpp +++ b/include/boost/python/copy_const_reference.hpp @@ -7,7 +7,7 @@ # define COPY_CONST_REFERENCE_DWA2002131_HPP # include # include -# include +# include namespace boost { namespace python { diff --git a/include/boost/python/copy_non_const_reference.hpp b/include/boost/python/copy_non_const_reference.hpp index dead736f..6f53fbdc 100644 --- a/include/boost/python/copy_non_const_reference.hpp +++ b/include/boost/python/copy_non_const_reference.hpp @@ -7,7 +7,7 @@ # define COPY_NON_CONST_REFERENCE_DWA2002131_HPP # include # include -# include +# include namespace boost { namespace python { diff --git a/include/boost/python/detail/caller.hpp b/include/boost/python/detail/caller.hpp index fe022961..d0b01b6e 100644 --- a/include/boost/python/detail/caller.hpp +++ b/include/boost/python/detail/caller.hpp @@ -20,26 +20,6 @@ namespace boost { namespace python namespace boost { namespace python { namespace detail { -// for "readable" error messages -template struct must_use_a_result_handler_to_wrap_functions_returning -# if defined(__GNUC__) && __GNUC__ >= 3 || defined(__EDG__) -{} -# endif -; - -struct to_python_generator -{ - template - struct apply - { - typedef typename mpl::select_type< - is_reference::value | is_pointer::value - , must_use_a_result_handler_to_wrap_functions_returning - , to_python - >::type type; - }; -}; - struct caller { typedef PyObject* result_type; diff --git a/include/boost/python/detail/msvc_typeinfo.hpp b/include/boost/python/detail/msvc_typeinfo.hpp new file mode 100644 index 00000000..2473023a --- /dev/null +++ b/include/boost/python/detail/msvc_typeinfo.hpp @@ -0,0 +1,99 @@ +// Copyright David Abrahams 2002. Permission to copy, use, +// modify, sell and distribute this software is granted provided this +// copyright notice appears in all copies. This software is provided +// "as is" without express or implied warranty, and with no claim as +// to its suitability for any purpose. +#ifndef MSVC_TYPEINFO_DWA200222_HPP +# define MSVC_TYPEINFO_DWA200222_HPP + +#include +#include + +// +// Fix for MSVC's broken typeid() implementation which doesn't strip +// decoration. This fix doesn't handle cv-qualified array types. It +// could probably be done, but I haven't figured it out yet. +// + +# if defined(BOOST_MSVC) && BOOST_MSVC <= 1300 || defined(BOOST_INTEL_CXX_VERSION) && BOOST_INTEL_CXX_VERSION <= 600 + +namespace boost { namespace python { namespace detail { + +typedef std::type_info const& typeinfo; + +templatestruct value_id_accessor; + +template<> +struct value_id_accessor<0> +{ + template + static typeinfo get(T*) { return typeid(T); } +}; + +template<> +struct value_id_accessor<1> +{ + template + static typeinfo get(T const*) { return typeid(T); } +}; + +template<> +struct value_id_accessor<2> +{ + template + static typeinfo get(T volatile*) { return typeid(T); } +}; + +template<> +struct value_id_accessor<3> +{ + template + static typeinfo get(T const volatile*) { return typeid(T); } +}; + +template struct bool_t{}; + +template +inline typeinfo typeid_nonref(boost::type* = 0) +{ + BOOST_STATIC_CONSTANT(bool, c = is_const::value); + BOOST_STATIC_CONSTANT(bool, v = is_volatile::value); + return value_id_accessor<(2 * v + c)>::get((T*)0); +} + +template +inline typeinfo typeid_ref(boost::type*, ...) +{ + return typeid_nonref(); +} + +template +inline typeinfo typeid_ref(boost::type*, T& (*)()) +{ + return typeid_nonref(); +} + +template +inline typeinfo typeid_array(bool_t, boost::type* = 0) +{ + typedef T (*x)(); + return typeid_ref((boost::type*)0, x(0)); +} + +template +inline typeinfo typeid_array(bool_t, boost::type* = 0) +{ + return typeid_nonref(); +} + +template +inline typeinfo msvc_typeid(boost::type* = 0) +{ + typedef bool_t::value> tag; + return typeid_array(tag(), (boost::type*)0); +} + +}}} // namespace boost::python::detail + +# endif // BOOST_MSVC +#endif // MSVC_TYPEINFO_DWA200222_HPP diff --git a/include/boost/python/detail/returning.hpp b/include/boost/python/detail/returning.hpp index c8533f9e..99bbc572 100644 --- a/include/boost/python/detail/returning.hpp +++ b/include/boost/python/detail/returning.hpp @@ -11,17 +11,10 @@ #ifndef RETURNING_DWA20011201_HPP # define RETURNING_DWA20011201_HPP -//# include # include # include # include # include -# include - -namespace boost { namespace python -{ - template struct to_python; -}} // namespace boost::python namespace boost { namespace python { namespace detail { diff --git a/include/boost/python/make_function.hpp b/include/boost/python/make_function.hpp index 90a5c12b..2943d96c 100644 --- a/include/boost/python/make_function.hpp +++ b/include/boost/python/make_function.hpp @@ -8,7 +8,6 @@ # include # include -# include # include # include # include diff --git a/include/boost/python/object/class_wrapper.hpp b/include/boost/python/object/class_wrapper.hpp index 26334bc7..4a52f290 100644 --- a/include/boost/python/object/class_wrapper.hpp +++ b/include/boost/python/object/class_wrapper.hpp @@ -6,21 +6,18 @@ #ifndef CLASS_WRAPPER_DWA20011221_HPP # define CLASS_WRAPPER_DWA20011221_HPP -# include # include # include -# include -# include +# include namespace boost { namespace python { namespace objects { template struct class_wrapper - : converter::to_python_converter + : to_python_converter > { class_wrapper(ref const& type_) - : converter::to_python_converter(convert) - , m_class_object_keeper(type_) + : m_class_object_keeper(type_) { assert(type_->ob_type == (PyTypeObject*)class_metatype().get()); m_class_object = (PyTypeObject*)type_.get(); @@ -31,9 +28,8 @@ struct class_wrapper // Don't call the type to do the construction, since that // would require the registration of an __init__ copy // constructor. Instead, just construct the object in place. - PyObject* raw_result = (PyObject*)PyObject_New( - instance, m_class_object); - + PyObject* raw_result = m_class_object->tp_alloc(m_class_object, 0); + if (raw_result == 0) return 0; @@ -41,6 +37,8 @@ struct class_wrapper // exceptions. ref result(raw_result, ref::allow_null()); + ((instance*)raw_result)->objects = 0; + // Build a value_holder to contain the object using the copy // constructor value_holder* p = new value_holder(raw_result, cref(x)); diff --git a/include/boost/python/to_python.hpp b/include/boost/python/to_python.hpp deleted file mode 100644 index e00346bb..00000000 --- a/include/boost/python/to_python.hpp +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright David Abrahams 2002. Permission to copy, use, -// modify, sell and distribute this software is granted provided this -// copyright notice appears in all copies. This software is provided -// "as is" without express or implied warranty, and with no claim as -// to its suitability for any purpose. -#ifndef TO_PYTHON_DWA2002128_HPP -# define TO_PYTHON_DWA2002128_HPP - -# include -# include - -namespace boost { namespace python { - -template -struct to_python - : converter::to_python_lookup::type> -{ -}; - -// specialization for PyObject* -template <> -struct to_python -{ - bool convertible() const { return true; } - PyObject* operator()(PyObject* source) const { return source; } -}; - -template <> -struct to_python -{ - bool convertible() const { return true; } - PyObject* operator()(PyObject* source) const { return source; } -}; - -}} // namespace boost::python - -#endif // TO_PYTHON_DWA2002128_HPP diff --git a/src/converter/builtin_converters.cpp b/src/converter/builtin_converters.cpp index c2ce3dae..26834635 100644 --- a/src/converter/builtin_converters.cpp +++ b/src/converter/builtin_converters.cpp @@ -200,7 +200,6 @@ namespace #define REGISTER_INT_CONVERTERS(U) register_int_converters() #define REGISTER_INT_CONVERTERS2(U) REGISTER_INT_CONVERTERS(signed U); REGISTER_INT_CONVERTERS(unsigned U) - void initialize_builtin_converters() { REGISTER_INT_CONVERTERS2(char); diff --git a/src/converter/from_python.cpp b/src/converter/from_python.cpp index 979ad935..2e844acf 100644 --- a/src/converter/from_python.cpp +++ b/src/converter/from_python.cpp @@ -5,6 +5,7 @@ // to its suitability for any purpose. #include +#include namespace boost { namespace python { namespace converter { @@ -14,14 +15,12 @@ from_python_converter_base::from_python_converter_base( ) : body(type) , m_convertible(checker) -{ - registry::insert(*this); -} -from_python_converter_base::~from_python_converter_base() { - if (can_unregister()) - registry::remove(*this); + // Insert this in the converter chain. + from_python_converter_base*& head = registry::from_python_chain(type); + m_next = head; + head = this; } }}} // namespace boost::python::converter diff --git a/src/converter/registry.cpp b/src/converter/registry.cpp index 5b4563a4..c90d709d 100644 --- a/src/converter/registry.cpp +++ b/src/converter/registry.cpp @@ -3,23 +3,32 @@ // copyright notice appears in all copies. This software is provided // "as is" without express or implied warranty, and with no claim as // to its suitability for any purpose. - -# include -# include -# include -# include -# include -# include -# include -# ifdef BOOST_PYTHON_TRACE -# include -# endif +#include +#include +#include +#include namespace boost { namespace python { namespace converter { namespace // { - typedef std::map registry_t; + // These are the elements stored in the registry + struct entry + { + entry(); + + // The unique to_python converter for the associated C++ type. + to_python_value_function m_to_python_converter; + + // The collection of from_python converters for the associated + // C++ type. + from_python_converter_base* m_from_python_converters; + + // The class object associated with this type + PyTypeObject* m_class_object; + }; + + typedef std::map registry_t; registry_t& entries() { @@ -35,10 +44,7 @@ namespace // } return registry; } -} // namespace -namespace registry -{ entry* find(type_id_t type) { return &entries()[type]; @@ -46,128 +52,40 @@ namespace registry entry::entry() : m_to_python_converter(0) + , m_from_python_converters(0) + , m_class_object(0) { } +} // namespace - entry::~entry() +namespace registry +{ + to_python_value_function const& to_python_function( + undecorated_type_id_t key) { - if (m_to_python_converter != 0) - m_to_python_converter->m_can_unregister = false; - - for (from_python_converters::iterator p = m_from_python_converters.begin() - ; p != m_from_python_converters.end() - ; ++p) - { - (*p)->m_can_unregister = false; - } - } - - from_python_converter_base const* - entry::get_from_python(PyObject* p, void*& data_out) const - { - for (from_python_converters::const_iterator q = m_from_python_converters.begin(), - finish = m_from_python_converters.end(); - q != finish; - ++q) - { - void* const data = (*q)->convertible(p); - if (data != 0) - { - data_out = data; - return *q; - break; - } - } - return 0; + return find(key)->m_to_python_converter; } - to_python_function_base entry::get_to_python() const + void insert(to_python_value_function f, undecorated_type_id_t source_t) { - return m_to_python_converter - ? m_to_python_converter->converter() - : 0; - } - - entry::from_python_converters::iterator entry::find(from_python_converter_base const& x) - { - return std::find(m_from_python_converters.begin(), m_from_python_converters.end(), &x); - } - - void entry::insert(from_python_converter_base& x) - { - from_python_converters::iterator p = this->find(x); - - if (p != m_from_python_converters.end()) - { - assert(!"converter already registered"); - throw std::runtime_error( - "trying to register unrapper which is already registered"); - } - - m_from_python_converters.push_back(&x); - } - - void entry::remove(from_python_converter_base& x) - { - from_python_converters::iterator p = find(x); - - // Be sure we're not removing a converter which hasn't been - // registered. - if (p == m_from_python_converters.end()) - { - assert(!"trying to unregister from_python_converter which is not registered"); - throw std::runtime_error( - "trying to unregister from_python_converter which is not registered"); - } - m_from_python_converters.erase(p); - } - - void entry::insert(to_python_converter_base& x) - { - assert(m_to_python_converter == 0); // we have a problem otherwise - if (m_to_python_converter != 0) + to_python_value_function& slot = find(source_t)->m_to_python_converter; + assert(slot == 0); // we have a problem otherwise + if (slot != 0) { throw std::runtime_error( "trying to register to_python_converter for a type which already has a registered to_python_converter"); } - m_to_python_converter = &x; + slot = f; + } + + from_python_converter_base*& from_python_chain(type_id_t key) + { + return find(key)->m_from_python_converters; } - void entry::remove(to_python_converter_base& x) + PyTypeObject*& class_object(undecorated_type_id_t key) { - assert(m_to_python_converter == &x); - if (m_to_python_converter != &x) - { - throw std::runtime_error( - "trying to unregister a to_python_converter which is not registered"); - } - m_to_python_converter = 0; - } - - void insert(to_python_converter_base& w) - { -# ifdef BOOST_PYTHON_TRACE - std::cout << "inserting to_python_converter for " << w.key() << std::endl; -# endif - find(w.key())->insert(w); - } - - void insert(from_python_converter_base& u) - { -# ifdef BOOST_PYTHON_TRACE - std::cout << "inserting from_python_converter for " << u.key() << std::endl; -# endif - find(u.key())->insert(u); - } - - void remove(to_python_converter_base& w) - { - find(w.key())->remove(w); - } - - void remove(from_python_converter_base& u) - { - find(u.key())->remove(u); + return find(key)->m_class_object; } } // namespace registry diff --git a/src/converter/to_python.cpp b/src/converter/to_python.cpp deleted file mode 100644 index 9cede51d..00000000 --- a/src/converter/to_python.cpp +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright David Abrahams 2002. Permission to copy, use, -// modify, sell and distribute this software is granted provided this -// copyright notice appears in all copies. This software is provided -// "as is" without express or implied warranty, and with no claim as -// to its suitability for any purpose. - -#include -#include - -namespace boost { namespace python { namespace converter { - -to_python_converter_base::to_python_converter_base(type_id_t key, to_python_function_base convert) - : body(key) - , m_convert(convert) -{ - registry::insert(*this); -} - -to_python_converter_base::~to_python_converter_base() -{ - registry::remove(*this); -} - -}}} // namespace boost::python::converter diff --git a/src/converter/type_id.cpp b/src/converter/type_id.cpp index 688dd2bc..904f30d0 100644 --- a/src/converter/type_id.cpp +++ b/src/converter/type_id.cpp @@ -21,18 +21,12 @@ BOOST_PYTHON_DECL std::ostream& operator<<(std::ostream& os, undecorated_type_id BOOST_PYTHON_DECL std::ostream& operator<<(std::ostream& os, type_id_t const& x) { os << x.m_base_type; - // VC6 mistakenly distinguishes typeid(X) from typeid(X const) - // from typeid(X&)... so the name is already correct. I have it - // from Jason Shirk that VC7.0 has the same bug but it will be - // fixed in 7.1 -# if !defined(BOOST_MSVC) || BOOST_MSVC > 1300 if (x.m_decoration & type_id_t::const_) os << " const"; if (x.m_decoration & type_id_t::volatile_) os << " volatile"; if (x.m_decoration & type_id_t::reference) os << "&"; -# endif return os; } diff --git a/src/object/class.cpp b/src/object/class.cpp index de3e32f5..5d1ecf01 100644 --- a/src/object/class.cpp +++ b/src/object/class.cpp @@ -6,7 +6,6 @@ #include #include #include -#include #include #include #include @@ -122,7 +121,7 @@ PyTypeObject class_type_object = { 0, /* tp_descr_set */ 0, /* tp_dictoffset */ 0, /* tp_init */ - 0, /* tp_alloc */ + PyType_GenericAlloc, /* tp_alloc */ PyType_GenericNew }; diff --git a/test/m1.cpp b/test/m1.cpp index b807dc43..b42742ab 100644 --- a/test/m1.cpp +++ b/test/m1.cpp @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -105,26 +106,19 @@ PyObject* new_simple() // are selected. // using boost::python::converter::from_python_data; +using boost::python::to_python_converter; -// Wrap a simple by converting it to a Simple -PyObject* simple_to_python(simple const& x) +// Wrap a simple by copying it into a Simple +struct simple_to_python + : to_python_converter { - SimpleObject* p = PyObject_New(SimpleObject, &SimpleType); - p->x = x; - return (PyObject*)p; -} - - -// wrap a mutable reference to a simple by converting it to a -// Simple. Normally we wouldn't do it this way, since modifications to -// the result clearly don't change the original object, but here we're -// just proving that the mechanism works. -PyObject* simple_ref_to_python(simple& x) -{ - SimpleObject* p = PyObject_New(SimpleObject, &SimpleType); - p->x = x; - return (PyObject*)p; -} + static PyObject* convert(simple const& x) + { + SimpleObject* p = PyObject_New(SimpleObject, &SimpleType); + p->x = x; + return (PyObject*)p; + } +}; int noddy_to_int(PyObject* p, from_python_data&) { @@ -184,16 +178,15 @@ struct D : B, C int x; }; -int take_a(A const& a) { return a.x; } -int take_b(B const& b) { return b.x; } -int take_c(C const& c) { return c.x; } -int take_d(D const& d) { return d.x; } +A take_a(A const& a) { return a; } +B take_b(B const& b) { return b; } +C take_c(C const& c) { return c; } +D take_d(D const& d) { return d; } BOOST_PYTHON_MODULE_INIT(m1) { using boost::python::module; using boost::python::class_; - using boost::python::converter::to_python_converter; using boost::python::converter::from_python_converter; using boost::python::reference_from_python; using boost::python::value_from_python; @@ -204,7 +197,7 @@ BOOST_PYTHON_MODULE_INIT(m1) using boost::mpl::type_list; // Create the converters; they are self-registering/unregistering. - static to_python_converter c1(simple_to_python); + static simple_to_python c1; static from_python_converter c2( &(boost::python::type_from_python<&NoddyType>::convertible), noddy_to_int); @@ -219,10 +212,7 @@ BOOST_PYTHON_MODULE_INIT(m1) , extract_simple_object > unwrap_simple; - - static to_python_converter simple_ref_wrapper(simple_ref_to_python); - module m1("m1"); typedef boost::python::objects::pointer_holder_generator< diff --git a/test/newtest.py b/test/newtest.py index 0636641b..4e6de142 100644 --- a/test/newtest.py +++ b/test/newtest.py @@ -73,8 +73,8 @@ are a complicated constructor and member function, respectively. >>> d = D() ------ ->>> take_a(a) -0 +>>> take_a(a).name() +'A' >>> try: ... take_b(a) @@ -92,11 +92,11 @@ are a complicated constructor and member function, respectively. ... else: print 'no exception' ------ ->>> take_a(b) -0 +>>> take_a(b).name() +'A' ->>> take_b(b) -1 +>>> take_b(b).name() +'B' >>> try: ... take_c(b) @@ -109,16 +109,16 @@ are a complicated constructor and member function, respectively. ... else: print 'no exception' ------- ->>> take_a(c) -0 +>>> take_a(c).name() +'A' >>> try: ... take_b(c) ... except: pass ... else: print 'no exception' ->>> take_c(c) -2 +>>> take_c(c).name() +'C' >>> try: ... take_d(c) @@ -126,14 +126,14 @@ are a complicated constructor and member function, respectively. ... else: print 'no exception' ------- ->>> take_a(d) -0 ->>> take_b(d) -1 ->>> take_c(d) -2 ->>> take_d(d) -3 +>>> take_a(d).name() +'A' +>>> take_b(d).name() +'B' +>>> take_c(d).name() +'C' +>>> take_d(d).name() +'D' """