@@ -143,6 +143,8 @@ inline PyTypeObject* make_default_metaclass() {
143143 return type;
144144}
145145
146+ // / Instance creation function for all pybind11 types. It only allocates space for the
147+ // / C++ object, but doesn't call the constructor -- an `__init__` function must do that.
146148extern " C" inline PyObject *pybind11_new (PyTypeObject *type, PyObject *, PyObject *) {
147149 PyObject *self = type->tp_alloc (type, 0 );
148150 auto instance = (instance_essentials<void > *) self;
@@ -154,6 +156,9 @@ extern "C" inline PyObject *pybind11_new(PyTypeObject *type, PyObject *, PyObjec
154156 return self;
155157}
156158
159+ // / An `__init__` function constructs the C++ object. Users should provide at least one
160+ // / of these using `py::init` or directly with `.def(__init__, ...)`. Otherwise, the
161+ // / following default function will be used which simply throws an exception.
157162extern " C" inline int pybind11_init (PyObject *self, PyObject *, PyObject *) {
158163 PyTypeObject *type = Py_TYPE (self);
159164 std::string msg;
@@ -166,6 +171,8 @@ extern "C" inline int pybind11_init(PyObject *self, PyObject *, PyObject *) {
166171 return -1 ;
167172}
168173
174+ // / Instance destructor function for all pybind11 types. It calls `type_info.dealloc`
175+ // / to destroy the C++ object itself, while the rest is Python bookkeeping.
169176extern " C" inline void pybind11_dealloc (PyObject *self) {
170177 auto instance = (instance_essentials<void > *) self;
171178 if (instance->value ) {
@@ -251,6 +258,7 @@ inline PyObject *internals::get_base(size_t instance_size) {
251258 }
252259}
253260
261+ // / dynamic_attr: Support for `d = instance.__dict__`.
254262extern " C" inline PyObject *pybind11_get_dict (PyObject *self, void *) {
255263 PyObject *&dict = *_PyObject_GetDictPtr (self);
256264 if (!dict)
@@ -259,6 +267,7 @@ extern "C" inline PyObject *pybind11_get_dict(PyObject *self, void *) {
259267 return dict;
260268}
261269
270+ // / dynamic_attr: Support for `instance.__dict__ = dict()`.
262271extern " C" inline int pybind11_set_dict (PyObject *self, PyObject *new_dict, void *) {
263272 if (!PyDict_Check (new_dict)) {
264273 PyErr_Format (PyExc_TypeError, " __dict__ must be set to a dictionary, not a '%.200s'" ,
@@ -272,23 +281,42 @@ extern "C" inline int pybind11_set_dict(PyObject *self, PyObject *new_dict, void
272281 return 0 ;
273282}
274283
275- static PyGetSetDef pybind11_getset[] = {
276- {const_cast <char *>(" __dict__" ), pybind11_get_dict, pybind11_set_dict, nullptr , nullptr },
277- {nullptr , nullptr , nullptr , nullptr , nullptr }
278- };
279-
284+ // / dynamic_attr: Allow the garbage collector to traverse the internal instance `__dict__`.
280285extern " C" inline int pybind11_traverse (PyObject *self, visitproc visit, void *arg) {
281286 PyObject *&dict = *_PyObject_GetDictPtr (self);
282287 Py_VISIT (dict);
283288 return 0 ;
284289}
285290
291+ // / dynamic_attr: Allow the GC to clear the dictionary.
286292extern " C" inline int pybind11_clear (PyObject *self) {
287293 PyObject *&dict = *_PyObject_GetDictPtr (self);
288294 Py_CLEAR (dict);
289295 return 0 ;
290296}
291297
298+ // / Give instances of this type a `__dict__` and opt into garbage collection.
299+ inline void enable_dynamic_attributes (PyHeapTypeObject *heap_type) {
300+ auto type = &heap_type->ht_type ;
301+ #if defined(PYPY_VERSION)
302+ pybind11_fail (std::string (type->tp_name ) + " : dynamic attributes are "
303+ " currently not supported in "
304+ " conjunction with PyPy!" );
305+ #endif
306+ type->tp_flags |= Py_TPFLAGS_HAVE_GC;
307+ type->tp_dictoffset = type->tp_basicsize ; // place dict at the end
308+ type->tp_basicsize += sizeof (PyObject *); // and allocate enough space for it
309+ type->tp_traverse = pybind11_traverse;
310+ type->tp_clear = pybind11_clear;
311+
312+ static PyGetSetDef getset[] = {
313+ {const_cast <char *>(" __dict__" ), pybind11_get_dict, pybind11_set_dict, nullptr , nullptr },
314+ {nullptr , nullptr , nullptr , nullptr , nullptr }
315+ };
316+ type->tp_getset = getset;
317+ }
318+
319+ // / buffer_protocol: Fill in the view as specified by flags.
292320extern " C" inline int pybind11_getbuffer (PyObject *obj, Py_buffer *view, int flags) {
293321 auto tinfo = get_type_info (Py_TYPE (obj));
294322 if (view == nullptr || obj == nullptr || !tinfo || !tinfo->get_buffer ) {
@@ -318,10 +346,22 @@ extern "C" inline int pybind11_getbuffer(PyObject *obj, Py_buffer *view, int fla
318346 return 0 ;
319347}
320348
349+ // / buffer_protocol: Release the resources of the buffer.
321350extern " C" inline void pybind11_releasebuffer (PyObject *, Py_buffer *view) {
322351 delete (buffer_info *) view->internal ;
323352}
324353
354+ // / Give this type a buffer interface.
355+ inline void enable_buffer_protocol (PyHeapTypeObject *heap_type) {
356+ heap_type->ht_type .tp_as_buffer = &heap_type->as_buffer ;
357+ #if PY_MAJOR_VERSION < 3
358+ heap_type->ht_type .tp_flags |= Py_TPFLAGS_HAVE_NEWBUFFER;
359+ #endif
360+
361+ heap_type->as_buffer .bf_getbuffer = pybind11_getbuffer;
362+ heap_type->as_buffer .bf_releasebuffer = pybind11_releasebuffer;
363+ }
364+
325365/* * Create a brand new Python type according to the `type_record` specification.
326366 Return value: New reference. */
327367inline PyObject* make_new_python_type (const type_record &rec) {
@@ -399,29 +439,11 @@ inline PyObject* make_new_python_type(const type_record &rec) {
399439 type->tp_flags |= Py_TPFLAGS_CHECKTYPES;
400440#endif
401441
402- /* Support dynamic attributes */
403- if (rec.dynamic_attr ) {
404- #if defined(PYPY_VERSION)
405- pybind11_fail (std::string (rec.name ) + " : dynamic attributes are "
406- " currently not supported in "
407- " conjunction with PyPy!" );
408- #endif
409- type->tp_dictoffset = type->tp_basicsize ; // place dict at the end
410- type->tp_basicsize += sizeof (PyObject *); // and allocate enough space for it
411- type->tp_getset = pybind11_getset;
412- type->tp_traverse = pybind11_traverse;
413- type->tp_clear = pybind11_clear;
414- type->tp_flags |= Py_TPFLAGS_HAVE_GC;
415- }
442+ if (rec.dynamic_attr )
443+ enable_dynamic_attributes (heap_type);
416444
417- if (rec.buffer_protocol ) {
418- type->tp_as_buffer = &heap_type->as_buffer ;
419- #if PY_MAJOR_VERSION < 3
420- type->tp_flags |= Py_TPFLAGS_HAVE_NEWBUFFER;
421- #endif
422- heap_type->as_buffer .bf_getbuffer = pybind11_getbuffer;
423- heap_type->as_buffer .bf_releasebuffer = pybind11_releasebuffer;
424- }
445+ if (rec.buffer_protocol )
446+ enable_buffer_protocol (heap_type);
425447
426448 if (PyType_Ready (type) < 0 )
427449 pybind11_fail (std::string (rec.name ) + " : PyType_Ready failed (" + error_string () + " )!" );
0 commit comments