@@ -143,6 +143,8 @@ inline PyTypeObject* make_default_metaclass() {
143
143
return type;
144
144
}
145
145
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.
146
148
extern " C" inline PyObject *pybind11_new (PyTypeObject *type, PyObject *, PyObject *) {
147
149
PyObject *self = type->tp_alloc (type, 0 );
148
150
auto instance = (instance_essentials<void > *) self;
@@ -154,6 +156,9 @@ extern "C" inline PyObject *pybind11_new(PyTypeObject *type, PyObject *, PyObjec
154
156
return self;
155
157
}
156
158
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.
157
162
extern " C" inline int pybind11_init (PyObject *self, PyObject *, PyObject *) {
158
163
PyTypeObject *type = Py_TYPE (self);
159
164
std::string msg;
@@ -166,6 +171,8 @@ extern "C" inline int pybind11_init(PyObject *self, PyObject *, PyObject *) {
166
171
return -1 ;
167
172
}
168
173
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.
169
176
extern " C" inline void pybind11_dealloc (PyObject *self) {
170
177
auto instance = (instance_essentials<void > *) self;
171
178
if (instance->value ) {
@@ -251,6 +258,7 @@ inline PyObject *internals::get_base(size_t instance_size) {
251
258
}
252
259
}
253
260
261
+ // / dynamic_attr: Support for `d = instance.__dict__`.
254
262
extern " C" inline PyObject *pybind11_get_dict (PyObject *self, void *) {
255
263
PyObject *&dict = *_PyObject_GetDictPtr (self);
256
264
if (!dict)
@@ -259,6 +267,7 @@ extern "C" inline PyObject *pybind11_get_dict(PyObject *self, void *) {
259
267
return dict;
260
268
}
261
269
270
+ // / dynamic_attr: Support for `instance.__dict__ = dict()`.
262
271
extern " C" inline int pybind11_set_dict (PyObject *self, PyObject *new_dict, void *) {
263
272
if (!PyDict_Check (new_dict)) {
264
273
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
272
281
return 0 ;
273
282
}
274
283
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__`.
280
285
extern " C" inline int pybind11_traverse (PyObject *self, visitproc visit, void *arg) {
281
286
PyObject *&dict = *_PyObject_GetDictPtr (self);
282
287
Py_VISIT (dict);
283
288
return 0 ;
284
289
}
285
290
291
+ // / dynamic_attr: Allow the GC to clear the dictionary.
286
292
extern " C" inline int pybind11_clear (PyObject *self) {
287
293
PyObject *&dict = *_PyObject_GetDictPtr (self);
288
294
Py_CLEAR (dict);
289
295
return 0 ;
290
296
}
291
297
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.
292
320
extern " C" inline int pybind11_getbuffer (PyObject *obj, Py_buffer *view, int flags) {
293
321
auto tinfo = get_type_info (Py_TYPE (obj));
294
322
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
318
346
return 0 ;
319
347
}
320
348
349
+ // / buffer_protocol: Release the resources of the buffer.
321
350
extern " C" inline void pybind11_releasebuffer (PyObject *, Py_buffer *view) {
322
351
delete (buffer_info *) view->internal ;
323
352
}
324
353
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
+
325
365
/* * Create a brand new Python type according to the `type_record` specification.
326
366
Return value: New reference. */
327
367
inline PyObject* make_new_python_type (const type_record &rec) {
@@ -399,29 +439,11 @@ inline PyObject* make_new_python_type(const type_record &rec) {
399
439
type->tp_flags |= Py_TPFLAGS_CHECKTYPES;
400
440
#endif
401
441
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);
416
444
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);
425
447
426
448
if (PyType_Ready (type) < 0 )
427
449
pybind11_fail (std::string (rec.name ) + " : PyType_Ready failed (" + error_string () + " )!" );
0 commit comments