mirror of
https://github.com/pybind/pybind11.git
synced 2026-05-12 17:26:13 +00:00
Merge pull request #437 from dean0x7d/dynamic-attrs
Add dynamic attribute support
This commit is contained in:
@@ -44,6 +44,9 @@ template <int Nurse, int Patient> struct keep_alive { };
|
||||
/// Annotation indicating that a class is involved in a multiple inheritance relationship
|
||||
struct multiple_inheritance { };
|
||||
|
||||
/// Annotation which enables dynamic attributes, i.e. adds `__dict__` to a class
|
||||
struct dynamic_attr { };
|
||||
|
||||
NAMESPACE_BEGIN(detail)
|
||||
/* Forward declarations */
|
||||
enum op_id : int;
|
||||
@@ -162,6 +165,9 @@ struct type_record {
|
||||
/// Multiple inheritance marker
|
||||
bool multiple_inheritance = false;
|
||||
|
||||
/// Does the class manage a __dict__?
|
||||
bool dynamic_attr = false;
|
||||
|
||||
PYBIND11_NOINLINE void add_base(const std::type_info *base, void *(*caster)(void *)) {
|
||||
auto base_info = detail::get_type_info(*base, false);
|
||||
if (!base_info) {
|
||||
@@ -292,6 +298,11 @@ struct process_attribute<multiple_inheritance> : process_attribute_default<multi
|
||||
static void init(const multiple_inheritance &, type_record *r) { r->multiple_inheritance = true; }
|
||||
};
|
||||
|
||||
template <>
|
||||
struct process_attribute<dynamic_attr> : process_attribute_default<dynamic_attr> {
|
||||
static void init(const dynamic_attr &, type_record *r) { r->dynamic_attr = true; }
|
||||
};
|
||||
|
||||
/***
|
||||
* Process a keep_alive call policy -- invokes keep_alive_impl during the
|
||||
* pre-call handler if both Nurse, Patient != 0 and use the post-call handler
|
||||
|
||||
@@ -573,6 +573,33 @@ public:
|
||||
};
|
||||
|
||||
NAMESPACE_BEGIN(detail)
|
||||
extern "C" inline PyObject *get_dict(PyObject *op, void *) {
|
||||
PyObject *&dict = *_PyObject_GetDictPtr(op);
|
||||
if (!dict) {
|
||||
dict = PyDict_New();
|
||||
}
|
||||
Py_XINCREF(dict);
|
||||
return dict;
|
||||
}
|
||||
|
||||
extern "C" inline int set_dict(PyObject *op, PyObject *new_dict, void *) {
|
||||
if (!PyDict_Check(new_dict)) {
|
||||
PyErr_Format(PyExc_TypeError, "__dict__ must be set to a dictionary, not a '%.200s'",
|
||||
Py_TYPE(new_dict)->tp_name);
|
||||
return -1;
|
||||
}
|
||||
PyObject *&dict = *_PyObject_GetDictPtr(op);
|
||||
Py_INCREF(new_dict);
|
||||
Py_CLEAR(dict);
|
||||
dict = new_dict;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static PyGetSetDef generic_getset[] = {
|
||||
{const_cast<char*>("__dict__"), get_dict, set_dict, nullptr, nullptr},
|
||||
{nullptr, nullptr, nullptr, nullptr, nullptr}
|
||||
};
|
||||
|
||||
/// Generic support for creating new Python heap types
|
||||
class generic_type : public object {
|
||||
template <typename...> friend class class_;
|
||||
@@ -684,6 +711,16 @@ protected:
|
||||
#endif
|
||||
type->ht_type.tp_flags &= ~Py_TPFLAGS_HAVE_GC;
|
||||
|
||||
/* Support dynamic attributes */
|
||||
if (rec->dynamic_attr) {
|
||||
type->ht_type.tp_flags |= Py_TPFLAGS_HAVE_GC;
|
||||
type->ht_type.tp_dictoffset = type->ht_type.tp_basicsize; // place the dict at the end
|
||||
type->ht_type.tp_basicsize += sizeof(PyObject *); // and allocate enough space for it
|
||||
type->ht_type.tp_getset = generic_getset;
|
||||
type->ht_type.tp_traverse = traverse;
|
||||
type->ht_type.tp_clear = clear;
|
||||
}
|
||||
|
||||
type->ht_type.tp_doc = tp_doc;
|
||||
|
||||
if (PyType_Ready(&type->ht_type) < 0)
|
||||
@@ -785,10 +822,27 @@ protected:
|
||||
|
||||
if (self->weakrefs)
|
||||
PyObject_ClearWeakRefs((PyObject *) self);
|
||||
|
||||
PyObject **dict_ptr = _PyObject_GetDictPtr((PyObject *) self);
|
||||
if (dict_ptr) {
|
||||
Py_CLEAR(*dict_ptr);
|
||||
}
|
||||
}
|
||||
Py_TYPE(self)->tp_free((PyObject*) self);
|
||||
}
|
||||
|
||||
static int traverse(PyObject *op, visitproc visit, void *arg) {
|
||||
PyObject *&dict = *_PyObject_GetDictPtr(op);
|
||||
Py_VISIT(dict);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int clear(PyObject *op) {
|
||||
PyObject *&dict = *_PyObject_GetDictPtr(op);
|
||||
Py_CLEAR(dict);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void install_buffer_funcs(
|
||||
buffer_info *(*get_buffer)(PyObject *, void *),
|
||||
void *get_buffer_data) {
|
||||
|
||||
Reference in New Issue
Block a user