Merge pull request #437 from dean0x7d/dynamic-attrs

Add dynamic attribute support
This commit is contained in:
Wenzel Jakob
2016-10-14 08:57:12 +02:00
committed by GitHub
7 changed files with 245 additions and 2 deletions

View File

@@ -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

View File

@@ -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) {