From 526d99f8322b10289754806fee4ee1ff35c5d3a8 Mon Sep 17 00:00:00 2001 From: Dave Abrahams Date: Sat, 7 Sep 2002 04:44:17 +0000 Subject: [PATCH] Embed C++ objects directly in Python objects [SVN r15192] --- include/boost/python/class.hpp | 20 ++- include/boost/python/converter/smart_ptr.hpp | 70 --------- include/boost/python/instance_holder.hpp | 12 ++ include/boost/python/object.hpp | 1 + include/boost/python/object/class.hpp | 28 ++-- include/boost/python/object/class_detail.hpp | 20 +++ include/boost/python/object/class_wrapper.hpp | 41 +----- include/boost/python/object/instance.hpp | 45 ++++++ include/boost/python/object/iterator.hpp | 1 + include/boost/python/object/make_holder.hpp | 16 +- include/boost/python/object/make_instance.hpp | 72 +++++++++ .../boost/python/object/pickle_support.hpp | 1 - include/boost/python/object/select_holder.hpp | 50 +++++-- include/boost/python/object/value_holder.hpp | 2 +- include/boost/python/object_core.hpp | 6 +- include/boost/python/to_python_indirect.hpp | 38 ++--- src/object/class.cpp | 138 ++++++++++++++++-- src/object/function.cpp | 10 +- test/cltree.cpp | 4 +- test/defaults.cpp | 3 +- test/m1.cpp | 6 - test/select_holder.cpp | 3 +- 22 files changed, 375 insertions(+), 212 deletions(-) delete mode 100644 include/boost/python/converter/smart_ptr.hpp create mode 100644 include/boost/python/object/class_detail.hpp create mode 100644 include/boost/python/object/instance.hpp create mode 100644 include/boost/python/object/make_instance.hpp diff --git a/include/boost/python/class.hpp b/include/boost/python/class.hpp index d215f33f..918de0ec 100644 --- a/include/boost/python/class.hpp +++ b/include/boost/python/class.hpp @@ -21,6 +21,7 @@ # include # include # include +# include # include # include # include @@ -56,7 +57,7 @@ namespace detail static inline void register_copy_constructor(mpl::bool_t const&, SelectHolder const& , T* = 0) { typedef typename SelectHolder::type holder; - force_instantiate(objects::class_wrapper()); + force_instantiate(objects::class_wrapper >()); SelectHolder::register_(); } @@ -96,7 +97,7 @@ class class_ : public objects::class_base X3 >::type>::type>::type held_type; - typedef objects::class_id class_id; + typedef objects::select_holder holder_selector; typedef typename detail::select_bases(); // Write the rest of the elements into succeeding positions. - class_id* p = ids + 1; + type_info* p = ids + 1; mpl::for_each::execute(&p); } BOOST_STATIC_CONSTANT( std::size_t, size = mpl::size::value + 1); - class_id ids[size]; + type_info ids[size]; }; friend struct id_vector; @@ -146,6 +146,7 @@ class class_ : public objects::class_base { this->register_(); this->def_init(InitArgs()); + this->set_instance_size(holder_selector::additional_size()); } @@ -155,6 +156,7 @@ class class_ : public objects::class_base { this->register_(); this->def_init(InitArgs(), initdoc); + this->set_instance_size(holder_selector::additional_size()); } // Wrap a member function or a non-member function which can take @@ -237,7 +239,7 @@ class class_ : public objects::class_base return this->def("__init__", python::make_constructor( // Using runtime type selection works around a CWPro7 bug. - objects::select_holder((held_type*)0).get() + holder_selector::execute((held_type*)0).get() ) ); } @@ -252,7 +254,7 @@ class class_ : public objects::class_base python::make_constructor( helper::get_policy(policy_or_doc) // Using runtime type selection works around a CWPro7 bug. - , objects::select_holder((held_type*)0).get() + , holder_selector::execute((held_type*)0).get() ) , helper::get_doc(policy_or_doc, doc) ); @@ -389,7 +391,7 @@ inline void class_::register_() const detail::register_copy_constructor( mpl::bool_t() - , objects::select_holder((held_type*)0) + , holder_selector::execute((held_type*)0) ); } @@ -402,6 +404,7 @@ inline class_::class_() this->register_(); detail::force_instantiate(sizeof(detail::assert_default_constructible(T()))); this->def_init(); + this->set_instance_size(holder_selector::additional_size()); } template @@ -419,6 +422,7 @@ inline class_::class_(char const* name, char const* doc) this->register_(); detail::force_instantiate(sizeof(detail::assert_default_constructible(T()))); this->def_init(); + this->set_instance_size(holder_selector::additional_size()); } template diff --git a/include/boost/python/converter/smart_ptr.hpp b/include/boost/python/converter/smart_ptr.hpp deleted file mode 100644 index bae4c2b8..00000000 --- a/include/boost/python/converter/smart_ptr.hpp +++ /dev/null @@ -1,70 +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 SMART_PTR_DWA2002123_HPP -# define SMART_PTR_DWA2002123_HPP - -# include -# include -namespace boost { namespace python { namespace converter { - -template -class smart_ptr_wrapper - : wrapper -{ - smart_ptr_wrapper(ref const& type_) - : m_class_object(type_) - { - assert(type_->ob_type == (PyTypeObject*)class_metatype().get()); - } - - PyObject* convert(Pointer x) const; - - private: - ref m_class_object; - - smart_ptr_converters(); -} - - -// -// implementations -// - -template -PyObject* smart_ptr_wrapper::convert(Pointer x) const -{ - if (x.operator->() == 0) - return detail::none(); - - // 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, (PyTypeObject*)m_class_object.get()); - - if (raw_result == 0) - return 0; - - // Everything's OK; Bypass NULL checks but guard against - // exceptions. - ref result(raw_result, ref::allow_null()); - - // Build a value_holder to contain the object using the copy - // constructor - objects::pointer_holder* - p = new objects::pointer_holder(x); - - // Install it in the instance - p->install(raw_result); - - // Return the new result - return result.release(); -} - - -}}} // namespace boost::python::converter - -#endif // SMART_PTR_DWA2002123_HPP diff --git a/include/boost/python/instance_holder.hpp b/include/boost/python/instance_holder.hpp index ea368c1a..28aa02e8 100755 --- a/include/boost/python/instance_holder.hpp +++ b/include/boost/python/instance_holder.hpp @@ -8,6 +8,8 @@ # include # include +# include +# include namespace boost { namespace python { @@ -25,6 +27,16 @@ struct BOOST_PYTHON_DECL instance_holder : private noncopyable void install(PyObject* inst) throw(); + // These functions should probably be located elsewhere. + + // Allocate storage for an object of the given size at the given + // offset in the Python instance<> object if bytes are available + // there. Otherwise allocate size bytes of heap memory. + static void* allocate(PyObject*, std::size_t offset, std::size_t size); + + // Deallocate storage from the heap if it was not carved out of + // the given Python object by allocate(), above. + static void deallocate(PyObject*, void* storage) throw(); private: instance_holder* m_next; }; diff --git a/include/boost/python/object.hpp b/include/boost/python/object.hpp index b2e0c6b3..dbdb7c0a 100755 --- a/include/boost/python/object.hpp +++ b/include/boost/python/object.hpp @@ -11,6 +11,7 @@ # include # include # include +# include namespace boost { namespace python { diff --git a/include/boost/python/object/class.hpp b/include/boost/python/object/class.hpp index cd7c25f4..69bc5b20 100644 --- a/include/boost/python/object/class.hpp +++ b/include/boost/python/object/class.hpp @@ -9,21 +9,14 @@ # include # include # include -# include -# include # include # include # include namespace boost { namespace python { -class module; - namespace objects { -// To identify a class, we don't need cv/reference decorations -typedef type_info class_id; - struct BOOST_PYTHON_DECL class_base : python::api::object { // constructor @@ -33,6 +26,7 @@ struct BOOST_PYTHON_DECL class_base : python::api::object , std::size_t num_types // A list of class_ids. The first is the type , class_id const*const types // this is wrapping. The rest are the types of // any bases. + , char const* doc = 0 // Docstring, if any. ); @@ -41,21 +35,17 @@ struct BOOST_PYTHON_DECL class_base : python::api::object void add_property(char const* name, object const& fget, object const& fset); void setattr(char const* name, object const&); void enable_pickling(bool getstate_manages_dict); + + // Set a special attribute in the class which tells Boost.Python + // to allocate extra bytes for embedded C++ objects in Python + // instances. + void set_instance_size(std::size_t bytes); + + // Set an __init__ function which throws an appropriate exception + // for abstract classes. void def_no_init(); }; -BOOST_PYTHON_DECL type_handle registered_class_object(class_id id); - -// Each extension instance will be one of these -struct instance -{ - PyObject_HEAD - instance_holder* objects; -}; - -BOOST_PYTHON_DECL type_handle class_metatype(); -BOOST_PYTHON_DECL type_handle class_type(); - }}} // namespace boost::python::objects #endif // CLASS_DWA20011214_HPP diff --git a/include/boost/python/object/class_detail.hpp b/include/boost/python/object/class_detail.hpp new file mode 100644 index 00000000..f4d4d51e --- /dev/null +++ b/include/boost/python/object/class_detail.hpp @@ -0,0 +1,20 @@ +// 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 CLASS_DETAIL_DWA200295_HPP +# define CLASS_DETAIL_DWA200295_HPP + +# include +# include + +namespace boost { namespace python { namespace objects { + +BOOST_PYTHON_DECL type_handle registered_class_object(type_info id); +BOOST_PYTHON_DECL type_handle class_metatype(); +BOOST_PYTHON_DECL type_handle class_type(); + +}}} // namespace boost::python::object + +#endif // CLASS_DETAIL_DWA200295_HPP diff --git a/include/boost/python/object/class_wrapper.hpp b/include/boost/python/object/class_wrapper.hpp index 723126a4..61364d9d 100644 --- a/include/boost/python/object/class_wrapper.hpp +++ b/include/boost/python/object/class_wrapper.hpp @@ -6,56 +6,21 @@ #ifndef CLASS_WRAPPER_DWA20011221_HPP # define CLASS_WRAPPER_DWA20011221_HPP -# include # include -# include # include namespace boost { namespace python { namespace objects { -template -struct copy_construct_instance -{ - static Holder* execute(PyObject* instance, Src const& x) - { - return new Holder(instance, cref(x)); - } -}; - // Used to convert objects of type Src to wrapped C++ classes by // building a new instance object and installing a Holder constructed // from the Src object. -template > +template struct class_wrapper - : to_python_converter > + : to_python_converter > { static PyObject* convert(Src const& x) { - // Get the class object associated with the wrapped type - typedef typename Holder::value_type value_type; - PyTypeObject* class_object = converter::registered::converters.class_object; - - // Don't call the type directly to do the construction, since - // that would require the registration of an appropriate - // __init__ function. - PyObject* raw_result = class_object->tp_alloc(class_object, 0); - - if (raw_result == 0) - return 0; - - // Everything's OK; Bypass NULL checks but guard against - // exceptions. - handle<> result(python::allow_null(raw_result)); - - // Build a value_holder to contain the object using the copy - // constructor - Holder* p = MakeHolder::execute(raw_result, x); - - // Install it in the instance - p->install(raw_result); - - // Return the new result - return result.release(); + return MakeInstance::execute(cref(x)); } }; diff --git a/include/boost/python/object/instance.hpp b/include/boost/python/object/instance.hpp new file mode 100644 index 00000000..c64ce33d --- /dev/null +++ b/include/boost/python/object/instance.hpp @@ -0,0 +1,45 @@ +// 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 INSTANCE_DWA200295_HPP +# define INSTANCE_DWA200295_HPP + +# include +# include +# include + +namespace boost { namespace python { namespace objects { + +// Each extension instance will be one of these +template +struct instance +{ + PyObject_VAR_HEAD + PyObject* dict; + PyObject* weakrefs; + instance_holder* objects; + + BOOST_STATIC_CONSTANT(std::size_t, alignment = alignment_of::value); + typedef typename type_with_alignment::type align_t; + + union + { + align_t align; + char bytes[sizeof(Data)]; + } storage; +}; + +template +struct additional_instance_size +{ + typedef instance instance_data; + typedef instance instance_char; + BOOST_STATIC_CONSTANT( + std::size_t, value = sizeof(instance_data) - offsetof(instance_char,storage)); +}; + +}}} // namespace boost::python::object + +#endif // INSTANCE_DWA200295_HPP diff --git a/include/boost/python/object/iterator.hpp b/include/boost/python/object/iterator.hpp index b41ba621..74af64c9 100644 --- a/include/boost/python/object/iterator.hpp +++ b/include/boost/python/object/iterator.hpp @@ -8,6 +8,7 @@ # include # include +# include # include # include # include diff --git a/include/boost/python/object/make_holder.hpp b/include/boost/python/object/make_holder.hpp index 58a185b0..1eab34e8 100644 --- a/include/boost/python/object/make_holder.hpp +++ b/include/boost/python/object/make_holder.hpp @@ -10,7 +10,6 @@ # define MAKE_HOLDER_DWA20011215_HPP # include -# include # include # include @@ -20,6 +19,8 @@ # include # include +# include + namespace boost { namespace python { namespace objects { template struct make_holder; @@ -57,8 +58,17 @@ struct make_holder PyObject* p BOOST_PP_COMMA_IF(N) BOOST_PYTHON_BINARY_ENUM(N, t, a)) { - (new Holder( - p BOOST_PP_REPEAT(N, BOOST_PYTHON_DO_FORWARD_ARG, nil)))->install(p); + typedef instance instance_t; + + void* memory = Holder::allocate(p, offsetof(instance_t, storage), sizeof(Holder)); + try { + (new (memory) Holder( + p BOOST_PP_REPEAT(N, BOOST_PYTHON_DO_FORWARD_ARG, nil)))->install(p); + } + catch(...) { + Holder::deallocate(p, memory); + throw; + } } }; }; diff --git a/include/boost/python/object/make_instance.hpp b/include/boost/python/object/make_instance.hpp new file mode 100644 index 00000000..d5e153b9 --- /dev/null +++ b/include/boost/python/object/make_instance.hpp @@ -0,0 +1,72 @@ +// 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 MAKE_INSTANCE_DWA200296_HPP +# define MAKE_INSTANCE_DWA200296_HPP + +# include +# include + +namespace boost { namespace python { namespace objects { + +template +struct make_instance +{ + typedef objects::instance instance_t; + + template + static PyObject* execute(Arg& x) + { + BOOST_STATIC_ASSERT(is_class::value); + PyTypeObject* type = converter::registered::converters.class_object; + + PyObject* raw_result = type->tp_alloc( + type, objects::additional_instance_size::value); + + if (raw_result != 0) + { + instance_t* result = (instance_t*)raw_result; + try + { + // construct the new C++ object and install the pointer + // in the Python object. + construct(result, x)->install(raw_result); + } + catch(...) + { + Py_DECREF(raw_result); // reclaim the Python object + throw; + } + + // Note the position of the internally-stored Holder, + // for the sake of destruction + result->ob_size = offsetof(instance_t, storage); + } + return raw_result; + } + + private: + // Kind of a hack to support code re-use. The first form is used + // to construct holders around pointers or smart pointers. The + // second form is used to construct holders around by-value + // returns. We have to pass a pointer to the owning Python object + // to the second form in order to make it forward the 2nd argument + // on to the constructor of its embedded T object. + template + static Holder* construct(instance_t* result, Arg& x) + { + return new ((void*)&result->storage) Holder(x); + } + + static Holder* construct(instance_t* result, reference_wrapper x) + { + return new ((void*)&result->storage) Holder((PyObject*)result, x); + } +}; + + +}}} // namespace boost::python::object + +#endif // MAKE_INSTANCE_DWA200296_HPP diff --git a/include/boost/python/object/pickle_support.hpp b/include/boost/python/object/pickle_support.hpp index 2e94faea..bae05138 100644 --- a/include/boost/python/object/pickle_support.hpp +++ b/include/boost/python/object/pickle_support.hpp @@ -6,7 +6,6 @@ #ifndef BOOST_PYTHON_OBJECT_PICKLE_SUPPORT_RWGK20020603_HPP #define BOOST_PYTHON_OBJECT_PICKLE_SUPPORT_RWGK20020603_HPP -#include #include #include diff --git a/include/boost/python/object/select_holder.hpp b/include/boost/python/object/select_holder.hpp index a2e50c69..6902f68d 100644 --- a/include/boost/python/object/select_holder.hpp +++ b/include/boost/python/object/select_holder.hpp @@ -12,10 +12,14 @@ # include # include # include +# include +# include # include # include # include +# include # include +# include namespace boost { namespace python { namespace objects { @@ -96,7 +100,7 @@ namespace detail objects::class_wrapper< Ptr , type - , construct_from_pointer>()); + , make_instance >()); python::detail::force_instantiate( instance_finder::registration); @@ -104,24 +108,40 @@ namespace detail }; } -template -inline detail::select_value_holder select_holder(python::detail::not_specified*, T* = 0, NotSpecified* = 0) -{ - return detail::select_value_holder(); -} - template -inline detail::select_value_holder select_holder(T*, Held* = 0) +struct select_holder { - return detail::select_value_holder(); -} + static inline std::size_t additional_size() + { + return additional_size_helper(execute((Held*)0)); + } + + static inline detail::select_value_holder + execute(python::detail::not_specified*) + { + return detail::select_value_holder(); + } + static inline detail::select_value_holder + execute(T*) + { + return detail::select_value_holder(); + } -template -detail::select_pointer_holder select_holder(void*, Ptr* = 0, T* = 0) -{ - return detail::select_pointer_holder(); -} + static inline detail::select_pointer_holder + execute(void*) + { + return detail::select_pointer_holder(); + } + + private: + template + static inline std::size_t additional_size_helper(Selector const&) + { + typedef typename Selector::type holder; + return additional_instance_size::value; + } +}; }}} // namespace boost::python::objects diff --git a/include/boost/python/object/value_holder.hpp b/include/boost/python/object/value_holder.hpp index 05a5c782..50477e3d 100644 --- a/include/boost/python/object/value_holder.hpp +++ b/include/boost/python/object/value_holder.hpp @@ -10,7 +10,7 @@ # define VALUE_HOLDER_DWA20011215_HPP # include -# include +# include # include # include # include diff --git a/include/boost/python/object_core.hpp b/include/boost/python/object_core.hpp index 29127fc9..98383c2f 100755 --- a/include/boost/python/object_core.hpp +++ b/include/boost/python/object_core.hpp @@ -9,7 +9,6 @@ # include # include -# include # include # include # include @@ -22,6 +21,11 @@ namespace boost { namespace python { +namespace converter +{ + template struct arg_to_python; +} + // Put this in an inner namespace so that the generalized operators won't take over namespace api { diff --git a/include/boost/python/to_python_indirect.hpp b/include/boost/python/to_python_indirect.hpp index 60b861b1..23ff8594 100644 --- a/include/boost/python/to_python_indirect.hpp +++ b/include/boost/python/to_python_indirect.hpp @@ -8,10 +8,12 @@ # include # include +# include # include # include # include # include +# include # include namespace boost { namespace python { @@ -32,7 +34,7 @@ namespace detail { struct make_owning_holder { - typedef instance_holder* result_type; + typedef PyObject* result_type; template static result_type execute(T* p) { @@ -41,20 +43,22 @@ namespace detail typedef boost::shared_ptr smart_pointer; # else typedef std::auto_ptr smart_pointer; -# endif - - return new objects::pointer_holder( - smart_pointer(p)); +# endif + typedef objects::pointer_holder holder_t; + + smart_pointer ptr(p); + return objects::make_instance::execute(ptr); } }; struct make_reference_holder { - typedef instance_holder* result_type; + typedef PyObject* result_type; template static result_type execute(T* p) { - return new objects::pointer_holder(p); + typedef objects::pointer_holder holder_t; + return objects::make_instance::execute(p); } }; @@ -99,26 +103,8 @@ inline PyObject* to_python_indirect::operator()(T x) const PyObject* const null_result = detail::null_pointer_to_none(x, 1L); if (null_result != 0) return null_result; - - PyObject* raw_result = type()->tp_alloc(type(), 0); - if (raw_result == 0) - return 0; - - // Everything's OK; Bypass NULL checks but guard against - // exceptions. - handle<> result(python::allow_null(raw_result)); - - // Build a value_holder to contain the object using the copy - // constructor - instance_holder* p = - detail::unwind_type(x); - - // Install it in the instance - p->install(raw_result); - - // Return the new result - return result.release(); + return detail::unwind_type(x); } template diff --git a/src/object/class.cpp b/src/object/class.cpp index 754ebe5a..8af51fc8 100644 --- a/src/object/class.cpp +++ b/src/object/class.cpp @@ -3,9 +3,11 @@ // 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 #include #include @@ -17,6 +19,9 @@ #include #include #include +#include +#include +#include namespace boost { namespace python { @@ -98,8 +103,8 @@ static PyTypeObject class_metatype_object = { void instance_holder::install(PyObject* self) throw() { assert(self->ob_type->ob_type == &class_metatype_object); - m_next = ((objects::instance*)self)->objects; - ((objects::instance*)self)->objects = this; + m_next = ((objects::instance<>*)self)->objects; + ((objects::instance<>*)self)->objects = this; } @@ -121,25 +126,89 @@ namespace objects { static void instance_dealloc(PyObject* inst) { - instance* kill_me = (instance*)inst; + instance<>* kill_me = (instance<>*)inst; for (instance_holder* p = kill_me->objects, *next; p != 0; p = next) { next = p->next(); - delete p; + p->~instance_holder(); + instance_holder::deallocate(inst, dynamic_cast(p)); } + // Python 2.2.1 won't add weak references automatically when + // tp_itemsize > 0, so we need to manage that + // ourselves. Accordingly, we also have to clean up the + // weakrefs ourselves. + if (kill_me->weakrefs != NULL) + PyObject_ClearWeakRefs(inst); + + Py_XDECREF(kill_me->dict); + inst->ob_type->tp_free(inst); } + + static PyObject * + instance_new(PyTypeObject* type_, PyObject* args, PyObject *kw) + { + // Attempt to find the __instance_size__ attribute. If not present, no problem. + PyObject* d = type_->tp_dict; + PyObject* instance_size_obj = PyObject_GetAttrString(d, "__instance_size__"); + + long instance_size = 0; + if (instance_size != 0) + instance_size = PyInt_AsLong(instance_size_obj); + + if (instance_size < 0) + instance_size = 0; + PyErr_Clear(); // Clear any errors that may have occurred. + + instance<>* result = (instance<>*)type_->tp_alloc(type_, instance_size); + if (result) + { + // Guido says we can use ob_size for any purpose we + // like, so we'll store the total size of the object + // there. A negative number indicates that the extra + // instance memory is not yet allocated to any holders. + result->ob_size = -(offsetof(instance<>,storage) + instance_size); + } + return (PyObject*)result; + } + + static PyObject* instance_get_dict(PyObject* op, void*) + { + instance<>* inst = downcast >(op); + if (inst->dict == 0) + inst->dict = PyDict_New(); + return python::xincref(inst->dict); + } + + static int instance_set_dict(PyObject* op, PyObject* dict, void*) + { + instance<>* inst = downcast >(op); + python::xdecref(inst->dict); + inst->dict = python::incref(dict); + return 0; + } } +static PyGetSetDef instance_getsets[] = { + {"__dict__", instance_get_dict, instance_set_dict, NULL}, + {0} +}; + + +static PyMemberDef instance_members[] = { + {"__weakref__", T_OBJECT, offsetof(instance<>, weakrefs), 0}, + {0} +}; + static PyTypeObject class_type_object = { PyObject_HEAD_INIT(0) //&class_metatype_object) 0, "Boost.Python.instance", - sizeof(instance), - 0, + offsetof(instance<>,storage), /* tp_basicsize */ + 1, /* tp_itemsize */ instance_dealloc, /* tp_dealloc */ 0, /* tp_print */ 0, /* tp_getattr */ @@ -161,20 +230,20 @@ namespace objects 0, /* tp_traverse */ 0, /* tp_clear */ 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ + offsetof(instance<>,weakrefs), /* tp_weaklistoffset */ 0, /* tp_iter */ 0, /* tp_iternext */ 0, /* tp_methods */ - 0, /* tp_members */ - 0, /* tp_getset */ - 0, //&PyBaseObject_Type, /* tp_base */ + instance_members, /* tp_members */ + instance_getsets, /* tp_getset */ + 0, //&PyBaseObject_Type, /* tp_base */ 0, /* tp_dict */ 0, /* tp_descr_get */ 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ + offsetof(instance<>,dict), /* tp_dictoffset */ 0, /* tp_init */ PyType_GenericAlloc, /* tp_alloc */ - PyType_GenericNew + instance_new /* tp_new */ }; BOOST_PYTHON_DECL type_handle class_type() @@ -195,7 +264,7 @@ namespace objects if (inst->ob_type->ob_type != &class_metatype_object) return 0; - instance* self = reinterpret_cast(inst); + instance<>* self = reinterpret_cast*>(inst); for (instance_holder* match = self->objects; match != 0; match = match->next()) { @@ -302,6 +371,11 @@ namespace objects this->attr("__doc__") = doc; } + void class_base::set_instance_size(std::size_t instance_size) + { + this->attr("__instance_size__") = instance_size; + } + extern "C" { // This declaration needed due to broken Python 2.2 headers @@ -369,4 +443,40 @@ namespace objects } } // namespace objects + +void* instance_holder::allocate(PyObject* self_, std::size_t holder_offset, std::size_t holder_size) +{ + assert(self_->ob_type->ob_type == &class_metatype_object); + objects::instance<>* self = (objects::instance<>*)self_; + + int total_size_needed = holder_offset + holder_size; + + if (-self->ob_size >= total_size_needed) + { + // holder_offset should at least point into the variable-sized part + assert(holder_offset >= offsetof(objects::instance<>,storage)); + + // Record the fact that the storage is occupied, noting where it starts + self->ob_size = holder_offset; + return (char*)self + holder_offset; + } + else + { + void* const result = PyMem_Malloc(holder_size); + if (result == 0) + throw std::bad_alloc(); + return result; + } +} + +void instance_holder::deallocate(PyObject* self_, void* storage) throw() +{ + assert(self_->ob_type->ob_type == &class_metatype_object); + objects::instance<>* self = (objects::instance<>*)self_; + if (storage != (char*)self + self->ob_size) + { + PyMem_Free(storage); + } +} + }} // namespace boost::python diff --git a/src/object/function.cpp b/src/object/function.cpp index 8aa39dbf..6d013b3a 100644 --- a/src/object/function.cpp +++ b/src/object/function.cpp @@ -301,11 +301,11 @@ extern "C" } } - static PyGetSetDef function_getsetlist[] = { - {"__name__", (getter)function_get_name, 0 }, - {"__doc__", (getter)function_get_doc, (setter)function_set_doc}, - {NULL} /* Sentinel */ - }; +static PyGetSetDef function_getsetlist[] = { + {"__name__", (getter)function_get_name, 0 }, + {"__doc__", (getter)function_get_doc, (setter)function_set_doc}, + {NULL} /* Sentinel */ +}; PyTypeObject function_type = { PyObject_HEAD_INIT(0) diff --git a/test/cltree.cpp b/test/cltree.cpp index 03e1be47..f7ea9eeb 100755 --- a/test/cltree.cpp +++ b/test/cltree.cpp @@ -52,7 +52,7 @@ public: BOOST_PYTHON_MODULE_INIT(cltree) { boost::python::class_("basic") - .def("__repr__",&basic::repr) + .def("__repr__",&basic::repr) ; boost::python::class_, boost::noncopyable>("constant") @@ -60,7 +60,7 @@ BOOST_PYTHON_MODULE_INIT(cltree) boost::python::class_("symbol") - ; + ; boost::python::class_, variable_wrapper>("variable") ; diff --git a/test/defaults.cpp b/test/defaults.cpp index 8cd3fe7b..b6d2a72f 100644 --- a/test/defaults.cpp +++ b/test/defaults.cpp @@ -17,7 +17,6 @@ #endif using namespace boost::python; -using namespace std; char const* const format = "int(%s); char(%s); string(%s); double(%s); "; @@ -169,7 +168,7 @@ BOOST_PYTHON_MODULE_INIT(defaults_ext) .def_init(args()) .def_init(args()) # endif - .def("get_state", &X::get_state) + .def("get_state", &X::get_state) .def("bar", &X::bar, X_bar_stubs()) .def("bar2", &X::bar2, X_bar_stubs2(), return_internal_reference<>()) .def("foo", (object(X::*)(std::string, bool) const)0, X_foo_2_stubs()) diff --git a/test/m1.cpp b/test/m1.cpp index a6cb7439..f09e4a93 100644 --- a/test/m1.cpp +++ b/test/m1.cpp @@ -216,12 +216,6 @@ BOOST_PYTHON_MODULE_INIT(m1) lvalue_from_pytype,&SimpleType>(); - // Insert the metaclass for all extension classes - scope().attr("xclass") = boost::python::objects::class_metatype(); - - // Insert the base class for all extension classes - scope().attr("xinst") = boost::python::objects::class_type(); - def("new_noddy", new_noddy); def("new_simple", new_simple); diff --git a/test/select_holder.cpp b/test/select_holder.cpp index f6b22baa..febbeb2d 100644 --- a/test/select_holder.cpp +++ b/test/select_holder.cpp @@ -8,6 +8,7 @@ #include #include #include +#include #include #define BOOST_INCLUDE_MAIN @@ -39,7 +40,7 @@ void assert_same(U* = 0, T* = 0) template void assert_holder(T* = 0, Held* = 0, Holder* = 0) { - assert_same(boost::python::objects::select_holder((Held*)0).get()); + assert_same(boost::python::objects::select_holder::execute((Held*)0).get()); } int test_main(int, char * [])