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