• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright David Abrahams 2001.
2 // Distributed under the Boost Software License, Version 1.0. (See
3 // accompanying file LICENSE_1_0.txt or copy at
4 // http://www.boost.org/LICENSE_1_0.txt)
5 
6 #include <boost/python/detail/prefix.hpp>
7 #include <boost/mpl/lambda.hpp> // #including this first is an intel6 workaround
8 
9 #include <boost/python/object/class.hpp>
10 #include <boost/python/object/instance.hpp>
11 #include <boost/python/object/class_detail.hpp>
12 #include <boost/python/scope.hpp>
13 #include <boost/python/converter/registry.hpp>
14 #include <boost/python/object/find_instance.hpp>
15 #include <boost/python/object/pickle_support.hpp>
16 #include <boost/python/detail/map_entry.hpp>
17 #include <boost/python/object.hpp>
18 #include <boost/python/object_protocol.hpp>
19 #include <boost/detail/binary_search.hpp>
20 #include <boost/python/self.hpp>
21 #include <boost/python/dict.hpp>
22 #include <boost/python/str.hpp>
23 #include <boost/python/ssize_t.hpp>
24 #include <functional>
25 #include <vector>
26 #include <cstddef>
27 #include <new>
28 #include <structmember.h>
29 
30 namespace boost { namespace python {
31 
32 # ifdef BOOST_PYTHON_SELF_IS_CLASS
33 namespace self_ns
34 {
35   self_t self;
36 }
37 # endif
38 
instance_holder()39 instance_holder::instance_holder()
40     : m_next(0)
41 {
42 }
43 
~instance_holder()44 instance_holder::~instance_holder()
45 {
46 }
47 
48 extern "C"
49 {
50   // This is copied from typeobject.c in the Python sources. Even though
51   // class_metatype_object doesn't set Py_TPFLAGS_HAVE_GC, that bit gets
52   // filled in by the base class initialization process in
53   // PyType_Ready(). However, tp_is_gc is *not* copied from the base
54   // type, making it assume that classes are GC-able even if (like
55   // class_type_object) they're statically allocated.
56   static int
type_is_gc(PyTypeObject * python_type)57   type_is_gc(PyTypeObject *python_type)
58   {
59       return python_type->tp_flags & Py_TPFLAGS_HEAPTYPE;
60   }
61 
62   // This is also copied from the Python sources.  We can't implement
63   // static_data as a subclass property effectively without it.
64   typedef struct {
65       PyObject_HEAD
66       PyObject *prop_get;
67       PyObject *prop_set;
68       PyObject *prop_del;
69       PyObject *prop_doc;
70       int getter_doc;
71   } propertyobject;
72 
73   // Copied from Python source and removed the part for setting docstring,
74   // since we don't have a setter for __doc__ and trying to set it will
75   // cause the init fail.
property_init(PyObject * self,PyObject * args,PyObject * kwds)76   static int property_init(PyObject *self, PyObject *args, PyObject *kwds)
77   {
78       PyObject *get = NULL, *set = NULL, *del = NULL, *doc = NULL;
79       static const char *kwlist[] = {"fget", "fset", "fdel", "doc", 0};
80       propertyobject *prop = (propertyobject *)self;
81 
82       if (!PyArg_ParseTupleAndKeywords(args, kwds, "|OOOO:property",
83                   const_cast<char **>(kwlist), &get, &set, &del, &doc))
84           return -1;
85 
86       if (get == Py_None)
87           get = NULL;
88       if (set == Py_None)
89           set = NULL;
90       if (del == Py_None)
91           del = NULL;
92 
93       Py_XINCREF(get);
94       Py_XINCREF(set);
95       Py_XINCREF(del);
96       Py_XINCREF(doc);
97 
98       prop->prop_get = get;
99       prop->prop_set = set;
100       prop->prop_del = del;
101       prop->prop_doc = doc;
102       prop->getter_doc = 0;
103 
104       return 0;
105   }
106 
107 
108   static PyObject *
static_data_descr_get(PyObject * self,PyObject *,PyObject *)109   static_data_descr_get(PyObject *self, PyObject * /*obj*/, PyObject * /*type*/)
110   {
111       propertyobject *gs = (propertyobject *)self;
112 
113       return PyObject_CallFunction(gs->prop_get, const_cast<char*>("()"));
114   }
115 
116   static int
static_data_descr_set(PyObject * self,PyObject *,PyObject * value)117   static_data_descr_set(PyObject *self, PyObject * /*obj*/, PyObject *value)
118   {
119       propertyobject *gs = (propertyobject *)self;
120       PyObject *func, *res;
121 
122       if (value == NULL)
123           func = gs->prop_del;
124       else
125           func = gs->prop_set;
126       if (func == NULL) {
127           PyErr_SetString(PyExc_AttributeError,
128                           value == NULL ?
129                           "can't delete attribute" :
130                           "can't set attribute");
131           return -1;
132       }
133       if (value == NULL)
134           res = PyObject_CallFunction(func, const_cast<char*>("()"));
135       else
136           res = PyObject_CallFunction(func, const_cast<char*>("(O)"), value);
137       if (res == NULL)
138           return -1;
139       Py_DECREF(res);
140       return 0;
141   }
142 }
143 
144 static PyTypeObject static_data_object = {
145     PyVarObject_HEAD_INIT(NULL, 0)
146     const_cast<char*>("Boost.Python.StaticProperty"),
147     sizeof(propertyobject),
148     0,
149     0,                                      /* tp_dealloc */
150     0,                                      /* tp_print */
151     0,                                      /* tp_getattr */
152     0,                                      /* tp_setattr */
153     0,                                      /* tp_compare */
154     0,                                      /* tp_repr */
155     0,                                      /* tp_as_number */
156     0,                                      /* tp_as_sequence */
157     0,                                      /* tp_as_mapping */
158     0,                                      /* tp_hash */
159     0,                                      /* tp_call */
160     0,                                      /* tp_str */
161     0,                                      /* tp_getattro */
162     0,                                      /* tp_setattro */
163     0,                                      /* tp_as_buffer */
164     Py_TPFLAGS_DEFAULT // | Py_TPFLAGS_HAVE_GC
165     | Py_TPFLAGS_BASETYPE,          /* tp_flags */
166     0,                                      /* tp_doc */
167     0,                                      /* tp_traverse */
168     0,                                      /* tp_clear */
169     0,                                      /* tp_richcompare */
170     0,                                      /* tp_weaklistoffset */
171     0,                                      /* tp_iter */
172     0,                                      /* tp_iternext */
173     0,                                      /* tp_methods */
174     0,                                      /* tp_members */
175     0,                                      /* tp_getset */
176     0, //&PyProperty_Type,                           /* tp_base */
177     0,                                      /* tp_dict */
178     static_data_descr_get,                                      /* tp_descr_get */
179     static_data_descr_set,                                      /* tp_descr_set */
180     0,                                      /* tp_dictoffset */
181     property_init,                                      /* tp_init */
182     0,                                      /* tp_alloc */
183     0, // filled in with type_new           /* tp_new */
184     0, // filled in with __PyObject_GC_Del  /* tp_free */
185     0,                                      /* tp_is_gc */
186     0,                                      /* tp_bases */
187     0,                                      /* tp_mro */
188     0,                                      /* tp_cache */
189     0,                                      /* tp_subclasses */
190     0,                                      /* tp_weaklist */
191 #if PYTHON_API_VERSION >= 1012
192     0                                       /* tp_del */
193 #endif
194 };
195 
196 namespace objects
197 {
198 #if PY_VERSION_HEX < 0x03000000
199   // XXX Not sure why this run into compiling error in Python 3
200   extern "C"
201   {
202       // This declaration needed due to broken Python 2.2 headers
203       extern DL_IMPORT(PyTypeObject) PyProperty_Type;
204   }
205 #endif
206 
static_data()207   BOOST_PYTHON_DECL PyObject* static_data()
208   {
209       if (static_data_object.tp_dict == 0)
210       {
211           Py_TYPE(&static_data_object) = &PyType_Type;
212           static_data_object.tp_base = &PyProperty_Type;
213           if (PyType_Ready(&static_data_object))
214               return 0;
215       }
216       return upcast<PyObject>(&static_data_object);
217   }
218 }
219 
220 extern "C"
221 {
222     // Ordinarily, descriptors have a certain assymetry: you can use
223     // them to read attributes off the class object they adorn, but
224     // writing the same attribute on the class object always replaces
225     // the descriptor in the class __dict__.  In order to properly
226     // represent C++ static data members, we need to allow them to be
227     // written through the class instance.  This function of the
228     // metaclass makes it possible.
229     static int
class_setattro(PyObject * obj,PyObject * name,PyObject * value)230     class_setattro(PyObject *obj, PyObject *name, PyObject* value)
231     {
232         // Must use "private" Python implementation detail
233         // _PyType_Lookup instead of PyObject_GetAttr because the
234         // latter will always end up calling the descr_get function on
235         // any descriptor it finds; we need the unadulterated
236         // descriptor here.
237         PyObject* a = _PyType_Lookup(downcast<PyTypeObject>(obj), name);
238 
239         // a is a borrowed reference or 0
240 
241         // If we found a static data descriptor, call it directly to
242         // force it to set the static data member
243         if (a != 0 && PyObject_IsInstance(a, objects::static_data()))
244             return Py_TYPE(a)->tp_descr_set(a, obj, value);
245         else
246             return PyType_Type.tp_setattro(obj, name, value);
247     }
248 }
249 
250 static PyTypeObject class_metatype_object = {
251     PyVarObject_HEAD_INIT(NULL, 0)
252     const_cast<char*>("Boost.Python.class"),
253     PyType_Type.tp_basicsize,
254     0,
255     0,                                      /* tp_dealloc */
256     0,                                      /* tp_print */
257     0,                                      /* tp_getattr */
258     0,                                      /* tp_setattr */
259     0,                                      /* tp_compare */
260     0,                                      /* tp_repr */
261     0,                                      /* tp_as_number */
262     0,                                      /* tp_as_sequence */
263     0,                                      /* tp_as_mapping */
264     0,                                      /* tp_hash */
265     0,                                      /* tp_call */
266     0,                                      /* tp_str */
267     0,                                      /* tp_getattro */
268     class_setattro,                         /* tp_setattro */
269     0,                                      /* tp_as_buffer */
270     Py_TPFLAGS_DEFAULT // | Py_TPFLAGS_HAVE_GC
271     | Py_TPFLAGS_BASETYPE,          /* tp_flags */
272     0,                                      /* tp_doc */
273     0,                                      /* tp_traverse */
274     0,                                      /* tp_clear */
275     0,                                      /* tp_richcompare */
276     0,                                      /* tp_weaklistoffset */
277     0,                                      /* tp_iter */
278     0,                                      /* tp_iternext */
279     0,                                      /* tp_methods */
280     0,                                      /* tp_members */
281     0,                                      /* tp_getset */
282     0, //&PyType_Type,                           /* tp_base */
283     0,                                      /* tp_dict */
284     0,                                      /* tp_descr_get */
285     0,                                      /* tp_descr_set */
286     0,                                      /* tp_dictoffset */
287     0,                                      /* tp_init */
288     0,                                      /* tp_alloc */
289     0, // filled in with type_new           /* tp_new */
290     0, // filled in with __PyObject_GC_Del  /* tp_free */
291     (inquiry)type_is_gc,                    /* tp_is_gc */
292     0,                                      /* tp_bases */
293     0,                                      /* tp_mro */
294     0,                                      /* tp_cache */
295     0,                                      /* tp_subclasses */
296     0,                                      /* tp_weaklist */
297 #if PYTHON_API_VERSION >= 1012
298     0                                       /* tp_del */
299 #endif
300 };
301 
302 // Install the instance data for a C++ object into a Python instance
303 // object.
install(PyObject * self)304 void instance_holder::install(PyObject* self) throw()
305 {
306     assert(PyType_IsSubtype(Py_TYPE(Py_TYPE(self)), &class_metatype_object));
307     m_next = ((objects::instance<>*)self)->objects;
308     ((objects::instance<>*)self)->objects = this;
309 }
310 
311 
312 namespace objects
313 {
314 // Get the metatype object for all extension classes.
class_metatype()315   BOOST_PYTHON_DECL type_handle class_metatype()
316   {
317       if (class_metatype_object.tp_dict == 0)
318       {
319           Py_TYPE(&class_metatype_object) = &PyType_Type;
320           class_metatype_object.tp_base = &PyType_Type;
321           if (PyType_Ready(&class_metatype_object))
322               return type_handle();
323       }
324       return type_handle(borrowed(&class_metatype_object));
325   }
326   extern "C"
327   {
instance_dealloc(PyObject * inst)328       static void instance_dealloc(PyObject* inst)
329       {
330           instance<>* kill_me = (instance<>*)inst;
331 
332           for (instance_holder* p = kill_me->objects, *next; p != 0; p = next)
333           {
334               next = p->next();
335               p->~instance_holder();
336               instance_holder::deallocate(inst, dynamic_cast<void*>(p));
337           }
338 
339           // Python 2.2.1 won't add weak references automatically when
340           // tp_itemsize > 0, so we need to manage that
341           // ourselves. Accordingly, we also have to clean up the
342           // weakrefs ourselves.
343           if (kill_me->weakrefs != NULL)
344             PyObject_ClearWeakRefs(inst);
345 
346           Py_XDECREF(kill_me->dict);
347 
348           Py_TYPE(inst)->tp_free(inst);
349       }
350 
351       static PyObject *
instance_new(PyTypeObject * type_,PyObject *,PyObject *)352       instance_new(PyTypeObject* type_, PyObject* /*args*/, PyObject* /*kw*/)
353       {
354           // Attempt to find the __instance_size__ attribute. If not present, no problem.
355           PyObject* d = type_->tp_dict;
356           PyObject* instance_size_obj = PyObject_GetAttrString(d, const_cast<char*>("__instance_size__"));
357 
358           ssize_t instance_size = instance_size_obj ?
359 #if PY_VERSION_HEX >= 0x03000000
360               PyLong_AsSsize_t(instance_size_obj) : 0;
361 #else
362               PyInt_AsLong(instance_size_obj) : 0;
363 #endif
364 
365           if (instance_size < 0)
366               instance_size = 0;
367 
368           PyErr_Clear(); // Clear any errors that may have occurred.
369 
370           instance<>* result = (instance<>*)type_->tp_alloc(type_, instance_size);
371           if (result)
372           {
373               // Guido says we can use ob_size for any purpose we
374               // like, so we'll store the total size of the object
375               // there. A negative number indicates that the extra
376               // instance memory is not yet allocated to any holders.
377 #if PY_VERSION_HEX >= 0x02060000
378               Py_SIZE(result) =
379 #else
380               result->ob_size =
381 #endif
382                   -(static_cast<int>(offsetof(instance<>,storage) + instance_size));
383           }
384           return (PyObject*)result;
385       }
386 
instance_get_dict(PyObject * op,void *)387       static PyObject* instance_get_dict(PyObject* op, void*)
388       {
389           instance<>* inst = downcast<instance<> >(op);
390           if (inst->dict == 0)
391               inst->dict = PyDict_New();
392           return python::xincref(inst->dict);
393       }
394 
instance_set_dict(PyObject * op,PyObject * dict,void *)395       static int instance_set_dict(PyObject* op, PyObject* dict, void*)
396       {
397           instance<>* inst = downcast<instance<> >(op);
398           python::xdecref(inst->dict);
399           inst->dict = python::incref(dict);
400           return 0;
401       }
402 
403   }
404 
405 
406   static PyGetSetDef instance_getsets[] = {
407       {const_cast<char*>("__dict__"),  instance_get_dict,  instance_set_dict, NULL, 0},
408       {0, 0, 0, 0, 0}
409   };
410 
411 
412   static PyMemberDef instance_members[] = {
413       {const_cast<char*>("__weakref__"), T_OBJECT, offsetof(instance<>, weakrefs), 0, 0},
414       {0, 0, 0, 0, 0}
415   };
416 
417   static PyTypeObject class_type_object = {
418       PyVarObject_HEAD_INIT(NULL, 0)
419       const_cast<char*>("Boost.Python.instance"),
420       offsetof(instance<>,storage),           /* tp_basicsize */
421       1,                                      /* tp_itemsize */
422       instance_dealloc,                       /* tp_dealloc */
423       0,                                      /* tp_print */
424       0,                                      /* tp_getattr */
425       0,                                      /* tp_setattr */
426       0,                                      /* tp_compare */
427       0,                                      /* tp_repr */
428       0,                                      /* tp_as_number */
429       0,                                      /* tp_as_sequence */
430       0,                                      /* tp_as_mapping */
431       0,                                      /* tp_hash */
432       0,                                      /* tp_call */
433       0,                                      /* tp_str */
434       0,                                      /* tp_getattro */
435       0,                                      /* tp_setattro */
436       0,                                      /* tp_as_buffer */
437       Py_TPFLAGS_DEFAULT // | Py_TPFLAGS_HAVE_GC
438       | Py_TPFLAGS_BASETYPE,          /* tp_flags */
439       0,                                      /* tp_doc */
440       0,                                      /* tp_traverse */
441       0,                                      /* tp_clear */
442       0,                                      /* tp_richcompare */
443       offsetof(instance<>,weakrefs),          /* tp_weaklistoffset */
444       0,                                      /* tp_iter */
445       0,                                      /* tp_iternext */
446       0,                                      /* tp_methods */
447       instance_members,                       /* tp_members */
448       instance_getsets,                       /* tp_getset */
449       0, //&PyBaseObject_Type,                /* tp_base */
450       0,                                      /* tp_dict */
451       0,                                      /* tp_descr_get */
452       0,                                      /* tp_descr_set */
453       offsetof(instance<>,dict),              /* tp_dictoffset */
454       0,                                      /* tp_init */
455       PyType_GenericAlloc,                    /* tp_alloc */
456       instance_new,                           /* tp_new */
457       0,                                      /* tp_free */
458       0,                                      /* tp_is_gc */
459       0,                                      /* tp_bases */
460       0,                                      /* tp_mro */
461       0,                                      /* tp_cache */
462       0,                                      /* tp_subclasses */
463       0,                                      /* tp_weaklist */
464 #if PYTHON_API_VERSION >= 1012
465       0                                       /* tp_del */
466 #endif
467   };
468 
class_type()469   BOOST_PYTHON_DECL type_handle class_type()
470   {
471       if (class_type_object.tp_dict == 0)
472       {
473           Py_TYPE(&class_type_object) = incref(class_metatype().get());
474           class_type_object.tp_base = &PyBaseObject_Type;
475           if (PyType_Ready(&class_type_object))
476               return type_handle();
477 //          class_type_object.tp_setattro = class_setattro;
478       }
479       return type_handle(borrowed(&class_type_object));
480   }
481 
482   BOOST_PYTHON_DECL void*
find_instance_impl(PyObject * inst,type_info type,bool null_shared_ptr_only)483   find_instance_impl(PyObject* inst, type_info type, bool null_shared_ptr_only)
484   {
485       if (!Py_TYPE(Py_TYPE(inst)) ||
486               !PyType_IsSubtype(Py_TYPE(Py_TYPE(inst)), &class_metatype_object))
487           return 0;
488 
489       instance<>* self = reinterpret_cast<instance<>*>(inst);
490 
491       for (instance_holder* match = self->objects; match != 0; match = match->next())
492       {
493           void* const found = match->holds(type, null_shared_ptr_only);
494           if (found)
495               return found;
496       }
497       return 0;
498   }
499 
module_prefix()500   object module_prefix()
501   {
502       return object(
503           PyObject_IsInstance(scope().ptr(), upcast<PyObject>(&PyModule_Type))
504           ? object(scope().attr("__name__"))
505           : api::getattr(scope(), "__module__", str())
506           );
507   }
508 
509   namespace
510   {
511     // Find a registered class object corresponding to id. Return a
512     // null handle if no such class is registered.
query_class(type_info id)513     inline type_handle query_class(type_info id)
514     {
515         converter::registration const* p = converter::registry::query(id);
516         return type_handle(
517             python::borrowed(
518                 python::allow_null(p ? p->m_class_object : 0))
519             );
520     }
521 
522     // Find a registered class corresponding to id. If not found,
523     // throw an appropriate exception.
get_class(type_info id)524     type_handle get_class(type_info id)
525     {
526         type_handle result(query_class(id));
527 
528         if (result.get() == 0)
529         {
530             object report("extension class wrapper for base class ");
531             report = report + id.name() + " has not been created yet";
532             PyErr_SetObject(PyExc_RuntimeError, report.ptr());
533             throw_error_already_set();
534         }
535         return result;
536     }
537 
538     // class_base constructor
539     //
540     // name -      the name of the new Python class
541     //
542     // num_types - one more than the number of declared bases
543     //
544     // types -     array of python::type_info, the first item
545     //             corresponding to the class being created, and the
546     //             rest corresponding to its declared bases.
547     //
548     inline object
new_class(char const * name,std::size_t num_types,type_info const * const types,char const * doc)549     new_class(char const* name, std::size_t num_types, type_info const* const types, char const* doc)
550     {
551       assert(num_types >= 1);
552 
553       // Build a tuple of the base Python type objects. If no bases
554       // were declared, we'll use our class_type() as the single base
555       // class.
556       ssize_t const num_bases = (std::max)(num_types - 1, static_cast<std::size_t>(1));
557       handle<> bases(PyTuple_New(num_bases));
558 
559       for (ssize_t i = 1; i <= num_bases; ++i)
560       {
561           type_handle c = (i >= static_cast<ssize_t>(num_types)) ? class_type() : get_class(types[i]);
562           // PyTuple_SET_ITEM steals this reference
563           PyTuple_SET_ITEM(bases.get(), static_cast<ssize_t>(i - 1), upcast<PyObject>(c.release()));
564       }
565 
566       // Call the class metatype to create a new class
567       dict d;
568 
569       object m = module_prefix();
570       if (m) d["__module__"] = m;
571 
572       if (doc != 0)
573           d["__doc__"] = doc;
574 
575       object result = object(class_metatype())(name, bases, d);
576       assert(PyType_IsSubtype(Py_TYPE(result.ptr()), &PyType_Type));
577 
578       if (scope().ptr() != Py_None)
579           scope().attr(name) = result;
580 
581       // For pickle. Will lead to informative error messages if pickling
582       // is not enabled.
583       result.attr("__reduce__") = object(make_instance_reduce_function());
584 
585       return result;
586     }
587   }
588 
class_base(char const * name,std::size_t num_types,type_info const * const types,char const * doc)589   class_base::class_base(
590       char const* name, std::size_t num_types, type_info const* const types, char const* doc)
591       : object(new_class(name, num_types, types, doc))
592   {
593       // Insert the new class object in the registry
594       converter::registration& converters = const_cast<converter::registration&>(
595           converter::registry::lookup(types[0]));
596 
597       // Class object is leaked, for now
598       converters.m_class_object = (PyTypeObject*)incref(this->ptr());
599   }
600 
copy_class_object(type_info const & src,type_info const & dst)601   BOOST_PYTHON_DECL void copy_class_object(type_info const& src, type_info const& dst)
602   {
603       converter::registration& dst_converters
604           = const_cast<converter::registration&>(converter::registry::lookup(dst));
605 
606       converter::registration const& src_converters = converter::registry::lookup(src);
607 
608       dst_converters.m_class_object = src_converters.m_class_object;
609   }
610 
set_instance_size(std::size_t instance_size)611   void class_base::set_instance_size(std::size_t instance_size)
612   {
613       this->attr("__instance_size__") = instance_size;
614   }
615 
add_property(char const * name,object const & fget,char const * docstr)616   void class_base::add_property(
617     char const* name, object const& fget, char const* docstr)
618   {
619       object property(
620           (python::detail::new_reference)
621           PyObject_CallFunction((PyObject*)&PyProperty_Type, const_cast<char*>("Osss"), fget.ptr(), (char*)NULL, (char*)NULL, docstr));
622 
623       this->setattr(name, property);
624   }
625 
add_property(char const * name,object const & fget,object const & fset,char const * docstr)626   void class_base::add_property(
627     char const* name, object const& fget, object const& fset, char const* docstr)
628   {
629       object property(
630           (python::detail::new_reference)
631           PyObject_CallFunction((PyObject*)&PyProperty_Type, const_cast<char*>("OOss"), fget.ptr(), fset.ptr(), (char*)NULL, docstr));
632 
633       this->setattr(name, property);
634   }
635 
add_static_property(char const * name,object const & fget)636   void class_base::add_static_property(char const* name, object const& fget)
637   {
638       object property(
639           (python::detail::new_reference)
640           PyObject_CallFunction(static_data(), const_cast<char*>("O"), fget.ptr())
641           );
642 
643       this->setattr(name, property);
644   }
645 
add_static_property(char const * name,object const & fget,object const & fset)646   void class_base::add_static_property(char const* name, object const& fget, object const& fset)
647   {
648       object property(
649           (python::detail::new_reference)
650           PyObject_CallFunction(static_data(), const_cast<char*>("OO"), fget.ptr(), fset.ptr()));
651 
652       this->setattr(name, property);
653   }
654 
setattr(char const * name,object const & x)655   void class_base::setattr(char const* name, object const& x)
656   {
657       if (PyObject_SetAttrString(this->ptr(), const_cast<char*>(name), x.ptr()) < 0)
658           throw_error_already_set();
659   }
660 
661   namespace
662   {
no_init(PyObject *,PyObject *)663     extern "C" PyObject* no_init(PyObject*, PyObject*)
664     {
665         ::PyErr_SetString(::PyExc_RuntimeError, const_cast<char*>("This class cannot be instantiated from Python"));
666         return NULL;
667     }
668     static ::PyMethodDef no_init_def = {
669         const_cast<char*>("__init__"), no_init, METH_VARARGS,
670         const_cast<char*>("Raises an exception\n"
671                           "This class cannot be instantiated from Python\n")
672     };
673   }
674 
def_no_init()675   void class_base::def_no_init()
676   {
677       handle<> f(::PyCFunction_New(&no_init_def, 0));
678       this->setattr("__init__", object(f));
679   }
680 
enable_pickling_(bool getstate_manages_dict)681   void class_base::enable_pickling_(bool getstate_manages_dict)
682   {
683       setattr("__safe_for_unpickling__", object(true));
684 
685       if (getstate_manages_dict)
686       {
687           setattr("__getstate_manages_dict__", object(true));
688       }
689   }
690 
691   namespace
692   {
callable_check(PyObject * callable)693     PyObject* callable_check(PyObject* callable)
694     {
695         if (PyCallable_Check(expect_non_null(callable)))
696             return callable;
697 
698         ::PyErr_Format(
699             PyExc_TypeError
700           , const_cast<char*>("staticmethod expects callable object; got an object of type %s, which is not callable")
701             , Py_TYPE(callable)->tp_name
702             );
703 
704         throw_error_already_set();
705         return 0;
706     }
707   }
708 
make_method_static(const char * method_name)709   void class_base::make_method_static(const char * method_name)
710   {
711       PyTypeObject* self = downcast<PyTypeObject>(this->ptr());
712       dict d((handle<>(borrowed(self->tp_dict))));
713 
714       object method(d[method_name]);
715 
716       this->attr(method_name) = object(
717           handle<>(
718               PyStaticMethod_New((callable_check)(method.ptr()) )
719               ));
720   }
721 
registered_class_object(type_info id)722   BOOST_PYTHON_DECL type_handle registered_class_object(type_info id)
723   {
724       return query_class(id);
725   }
726 } // namespace objects
727 
728 
allocate(PyObject * self_,std::size_t holder_offset,std::size_t holder_size)729 void* instance_holder::allocate(PyObject* self_, std::size_t holder_offset, std::size_t holder_size)
730 {
731     assert(PyType_IsSubtype(Py_TYPE(Py_TYPE(self_)), &class_metatype_object));
732     objects::instance<>* self = (objects::instance<>*)self_;
733 
734     int total_size_needed = holder_offset + holder_size;
735 
736     if (-Py_SIZE(self) >= total_size_needed)
737     {
738         // holder_offset should at least point into the variable-sized part
739         assert(holder_offset >= offsetof(objects::instance<>,storage));
740 
741         // Record the fact that the storage is occupied, noting where it starts
742         Py_SIZE(self) = holder_offset;
743         return (char*)self + holder_offset;
744     }
745     else
746     {
747         void* const result = PyMem_Malloc(holder_size);
748         if (result == 0)
749             throw std::bad_alloc();
750         return result;
751     }
752 }
753 
deallocate(PyObject * self_,void * storage)754 void instance_holder::deallocate(PyObject* self_, void* storage) throw()
755 {
756     assert(PyType_IsSubtype(Py_TYPE(Py_TYPE(self_)), &class_metatype_object));
757     objects::instance<>* self = (objects::instance<>*)self_;
758     if (storage != (char*)self + Py_SIZE(self))
759     {
760         PyMem_Free(storage);
761     }
762 }
763 
764 }} // namespace boost::python
765