class.cpp
来自「Boost provides free peer-reviewed portab」· C++ 代码 · 共 718 行 · 第 1/2 页
CPP
718 行
// Copyright David Abrahams 2001.// Distributed under the Boost Software License, Version 1.0. (See// accompanying file LICENSE_1_0.txt or copy at// http://www.boost.org/LICENSE_1_0.txt)#include <boost/python/detail/prefix.hpp>#include <boost/mpl/lambda.hpp> // #including this first is an intel6 workaround#include <boost/python/object/class.hpp>#include <boost/python/object/instance.hpp>#include <boost/python/object/class_detail.hpp>#include <boost/python/scope.hpp>#include <boost/python/converter/registry.hpp>#include <boost/python/object/find_instance.hpp>#include <boost/python/object/pickle_support.hpp>#include <boost/python/detail/map_entry.hpp>#include <boost/python/object.hpp>#include <boost/python/object_protocol.hpp>#include <boost/detail/binary_search.hpp>#include <boost/python/self.hpp>#include <boost/python/dict.hpp>#include <boost/python/str.hpp>#include <boost/python/ssize_t.hpp>#include <functional>#include <vector>#include <cstddef>#include <new>#include <structmember.h>namespace boost { namespace python {# ifdef BOOST_PYTHON_SELF_IS_CLASSnamespace self_ns{ self_t self;}# endif instance_holder::instance_holder() : m_next(0){}instance_holder::~instance_holder(){}extern "C"{ // This is copied from typeobject.c in the Python sources. Even though // class_metatype_object doesn't set Py_TPFLAGS_HAVE_GC, that bit gets // filled in by the base class initialization process in // PyType_Ready(). However, tp_is_gc is *not* copied from the base // type, making it assume that classes are GC-able even if (like // class_type_object) they're statically allocated. static int type_is_gc(PyTypeObject *python_type) { return python_type->tp_flags & Py_TPFLAGS_HEAPTYPE; } // This is also copied from the Python sources. We can't implement // static_data as a subclass property effectively without it. typedef struct { PyObject_HEAD PyObject *prop_get; PyObject *prop_set; PyObject *prop_del; PyObject *prop_doc; } propertyobject; static PyObject * static_data_descr_get(PyObject *self, PyObject * /*obj*/, PyObject * /*type*/) { propertyobject *gs = (propertyobject *)self; return PyObject_CallFunction(gs->prop_get, "()"); } static int static_data_descr_set(PyObject *self, PyObject * /*obj*/, PyObject *value) { propertyobject *gs = (propertyobject *)self; PyObject *func, *res; if (value == NULL) func = gs->prop_del; else func = gs->prop_set; if (func == NULL) { PyErr_SetString(PyExc_AttributeError, value == NULL ? "can't delete attribute" : "can't set attribute"); return -1; } if (value == NULL) res = PyObject_CallFunction(func, "()"); else res = PyObject_CallFunction(func, "(O)", value); if (res == NULL) return -1; Py_DECREF(res); return 0; }}static PyTypeObject static_data_object = { PyObject_HEAD_INIT(0)//&PyType_Type) 0, "Boost.Python.StaticProperty", PyType_Type.tp_basicsize, 0, 0, /* tp_dealloc */ 0, /* tp_print */ 0, /* tp_getattr */ 0, /* tp_setattr */ 0, /* tp_compare */ 0, /* tp_repr */ 0, /* tp_as_number */ 0, /* tp_as_sequence */ 0, /* tp_as_mapping */ 0, /* tp_hash */ 0, /* tp_call */ 0, /* tp_str */ 0, /* tp_getattro */ 0, /* tp_setattro */ 0, /* tp_as_buffer */ Py_TPFLAGS_DEFAULT // | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_BASETYPE, /* tp_flags */ 0, /* tp_doc */ 0, /* tp_traverse */ 0, /* tp_clear */ 0, /* tp_richcompare */ 0, /* tp_weaklistoffset */ 0, /* tp_iter */ 0, /* tp_iternext */ 0, /* tp_methods */ 0, /* tp_members */ 0, /* tp_getset */ 0, //&PyProperty_Type, /* tp_base */ 0, /* tp_dict */ static_data_descr_get, /* tp_descr_get */ static_data_descr_set, /* tp_descr_set */ 0, /* tp_dictoffset */ 0, /* tp_init */ 0, /* tp_alloc */ 0, // filled in with type_new /* tp_new */ 0, // filled in with __PyObject_GC_Del /* tp_free */ (inquiry)type_is_gc, /* tp_is_gc */ 0, /* tp_bases */ 0, /* tp_mro */ 0, /* tp_cache */ 0, /* tp_subclasses */ 0, /* tp_weaklist */#if PYTHON_API_VERSION >= 1012 0 /* tp_del */#endif};namespace objects{ extern "C" { // This declaration needed due to broken Python 2.2 headers extern DL_IMPORT(PyTypeObject) PyProperty_Type; } BOOST_PYTHON_DECL PyObject* static_data() { if (static_data_object.tp_dict == 0) { static_data_object.ob_type = &PyType_Type; static_data_object.tp_base = &PyProperty_Type; if (PyType_Ready(&static_data_object)) return 0; } return upcast<PyObject>(&static_data_object); }} extern "C"{ // Ordinarily, descriptors have a certain assymetry: you can use // them to read attributes off the class object they adorn, but // writing the same attribute on the class object always replaces // the descriptor in the class __dict__. In order to properly // represent C++ static data members, we need to allow them to be // written through the class instance. This function of the // metaclass makes it possible. static int class_setattro(PyObject *obj, PyObject *name, PyObject* value) { // Must use "private" Python implementation detail // _PyType_Lookup instead of PyObject_GetAttr because the // latter will always end up calling the descr_get function on // any descriptor it finds; we need the unadulterated // descriptor here. PyObject* a = _PyType_Lookup(downcast<PyTypeObject>(obj), name); // a is a borrowed reference or 0 // If we found a static data descriptor, call it directly to // force it to set the static data member if (a != 0 && PyObject_IsInstance(a, objects::static_data())) return a->ob_type->tp_descr_set(a, obj, value); else return PyType_Type.tp_setattro(obj, name, value); }}static PyTypeObject class_metatype_object = { PyObject_HEAD_INIT(0)//&PyType_Type) 0, "Boost.Python.class", PyType_Type.tp_basicsize, 0, 0, /* tp_dealloc */ 0, /* tp_print */ 0, /* tp_getattr */ 0, /* tp_setattr */ 0, /* tp_compare */ 0, /* tp_repr */ 0, /* tp_as_number */ 0, /* tp_as_sequence */ 0, /* tp_as_mapping */ 0, /* tp_hash */ 0, /* tp_call */ 0, /* tp_str */ 0, /* tp_getattro */ class_setattro, /* tp_setattro */ 0, /* tp_as_buffer */ Py_TPFLAGS_DEFAULT // | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_BASETYPE, /* tp_flags */ 0, /* tp_doc */ 0, /* tp_traverse */ 0, /* tp_clear */ 0, /* tp_richcompare */ 0, /* tp_weaklistoffset */ 0, /* tp_iter */ 0, /* tp_iternext */ 0, /* tp_methods */ 0, /* tp_members */ 0, /* tp_getset */ 0, //&PyType_Type, /* tp_base */ 0, /* tp_dict */ 0, /* tp_descr_get */ 0, /* tp_descr_set */ 0, /* tp_dictoffset */ 0, /* tp_init */ 0, /* tp_alloc */ 0, // filled in with type_new /* tp_new */ 0, // filled in with __PyObject_GC_Del /* tp_free */ (inquiry)type_is_gc, /* tp_is_gc */ 0, /* tp_bases */ 0, /* tp_mro */ 0, /* tp_cache */ 0, /* tp_subclasses */ 0, /* tp_weaklist */#if PYTHON_API_VERSION >= 1012 0 /* tp_del */#endif};// Install the instance data for a C++ object into a Python instance// object.void instance_holder::install(PyObject* self) throw(){ assert(self->ob_type->ob_type == &class_metatype_object); m_next = ((objects::instance<>*)self)->objects; ((objects::instance<>*)self)->objects = this;}namespace objects{// Get the metatype object for all extension classes. BOOST_PYTHON_DECL type_handle class_metatype() { if (class_metatype_object.tp_dict == 0) { class_metatype_object.ob_type = &PyType_Type; class_metatype_object.tp_base = &PyType_Type; if (PyType_Ready(&class_metatype_object)) return type_handle(); } return type_handle(borrowed(&class_metatype_object)); } extern "C" { static void instance_dealloc(PyObject* inst) { instance<>* kill_me = (instance<>*)inst; for (instance_holder* p = kill_me->objects, *next; p != 0; p = next) { next = p->next(); p->~instance_holder(); instance_holder::deallocate(inst, dynamic_cast<void*>(p)); } // Python 2.2.1 won't add weak references automatically when // tp_itemsize > 0, so we need to manage that // ourselves. Accordingly, we also have to clean up the // weakrefs ourselves. if (kill_me->weakrefs != NULL) PyObject_ClearWeakRefs(inst); Py_XDECREF(kill_me->dict); inst->ob_type->tp_free(inst); } static PyObject * instance_new(PyTypeObject* type_, PyObject* /*args*/, PyObject* /*kw*/) { // Attempt to find the __instance_size__ attribute. If not present, no problem. PyObject* d = type_->tp_dict; PyObject* instance_size_obj = PyObject_GetAttrString(d, "__instance_size__"); long instance_size = instance_size_obj ? PyInt_AsLong(instance_size_obj) : 0; if (instance_size < 0) instance_size = 0; PyErr_Clear(); // Clear any errors that may have occurred. instance<>* result = (instance<>*)type_->tp_alloc(type_, instance_size); if (result) { // Guido says we can use ob_size for any purpose we // like, so we'll store the total size of the object // there. A negative number indicates that the extra // instance memory is not yet allocated to any holders. result->ob_size = -(static_cast<int>(offsetof(instance<>,storage) + instance_size)); } return (PyObject*)result; } static PyObject* instance_get_dict(PyObject* op, void*) { instance<>* inst = downcast<instance<> >(op); if (inst->dict == 0) inst->dict = PyDict_New(); return python::xincref(inst->dict); } static int instance_set_dict(PyObject* op, PyObject* dict, void*) { instance<>* inst = downcast<instance<> >(op); python::xdecref(inst->dict); inst->dict = python::incref(dict); return 0; } } static PyGetSetDef instance_getsets[] = {
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?