text: // 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_CLASS
  namespace 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;
        int getter_doc;
    } propertyobject;
  
    // Copied from Python source and removed the part for setting docstring,
    // since we don't have a setter for __doc__ and trying to set it will
    // cause the init fail.
    static int property_init(PyObject *self, PyObject *args, PyObject *kwds)
    {
        PyObject *get = NULL, *set = NULL, *del = NULL, *doc = NULL;
        static const char *kwlist[] = {"fget", "fset", "fdel", "doc", 0};
        propertyobject *prop = (propertyobject *)self;
  
        if (!PyArg_ParseTupleAndKeywords(args, kwds, "|OOOO:property",
                    const_cast<char **>(kwlist), &get, &set, &del, &doc))
            return -1;
  
        if (get == Py_None)
            get = NULL;
        if (set == Py_None)
            set = NULL;
        if (del == Py_None)
            del = NULL;
  
        Py_XINCREF(get);
        Py_XINCREF(set);
        Py_XINCREF(del);
        Py_XINCREF(doc);
  
        prop->prop_get = get;
        prop->prop_set = set;
        prop->prop_del = del;
        prop->prop_doc = doc;
        prop->getter_doc = 0;
  
        return 0;
    }
  
   
    static PyObject *
    static_data_descr_get(PyObject *self, PyObject * /*obj*/, PyObject * /*type*/)
    {
        propertyobject *gs = (propertyobject *)self;
  
        return PyObject_CallFunction(gs->prop_get, const_cast<char*>("()"));
    }
  
    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, const_cast<char*>("()"));
        else
            res = PyObject_CallFunction(func, const_cast<char*>("(O)"), value);
        if (res == NULL)
            return -1;
        Py_DECREF(res);
        return 0;
    }
  }
  
  static PyTypeObject static_data_object = {
      PyVarObject_HEAD_INIT(NULL, 0)
      const_cast<char*>("Boost.Python.StaticProperty"),
      sizeof(propertyobject),
      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 */
      property_init,                                      /* tp_init */
      0,                                      /* tp_alloc */
      0, // filled in with type_new           /* tp_new */
      0, // filled in with __PyObject_GC_Del  /* tp_free */
      0,                                      /* 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
  {
  #if PY_VERSION_HEX < 0x03000000
    // XXX Not sure why this run into compiling error in Python 3
    extern "C"
    {
        // This declaration needed due to broken Python 2.2 headers
        extern DL_IMPORT(PyTypeObject) PyProperty_Type;
    }
  #endif
  
    BOOST_PYTHON_DECL PyObject* static_data()
    {
        if (static_data_object.tp_dict == 0)
        {
            Py_TYPE(&static_data_object) = &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 Py_TYPE(a)->tp_descr_set(a, obj, value);
          else
              return PyType_Type.tp_setattro(obj, name, value);
      }
  }
  
  static PyTypeObject class_metatype_object = {
      PyVarObject_HEAD_INIT(NULL, 0)
      const_cast<char*>("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(PyType_IsSubtype(Py_TYPE(Py_TYPE(self)), &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)
        {
            Py_TYPE(&class_metatype_object) = &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);
            
            Py_TYPE(inst)->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, const_cast<char*>("__instance_size__"));
  
            ssize_t instance_size = instance_size_obj ? 
  #if PY_VERSION_HEX >= 0x03000000
                PyLong_AsSsize_t(instance_size_obj) : 0;
  #else
                PyInt_AsLong(instance_size_obj) : 0;
  #endif
            
            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.
  #if PY_VERSION_HEX >= 0x02060000
                Py_SIZE(result) =
  #else
                result->ob_size =
  #endif
                    -(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[] = {
        {const_cast<char*>("__dict__"),  instance_get_dict,  instance_set_dict, NULL, 0},
        {0, 0, 0, 0, 0}
    };
  
    
    static PyMemberDef instance_members[] = {
        {const_cast<char*>("__weakref__"), T_OBJECT, offsetof(instance<>, weakrefs), 0, 0},
        {0, 0, 0, 0, 0}
    };
  
    static PyTypeObject class_type_object = {
        PyVarObject_HEAD_INIT(NULL, 0)
        const_cast<char*>("Boost.Python.instance"),
        offsetof(instance<>,storage),           /* tp_basicsize */
        1,                                      /* tp_itemsize */
        instance_dealloc,                       /* 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 */
        offsetof(instance<>,weakrefs),          /* tp_weaklistoffset */
        0,                                      /* tp_iter */
        0,                                      /* tp_iternext */
        0,                                      /* tp_methods */
        instance_members,                       /* tp_members */
        instance_getsets,                       /* tp_getset */
        0, //&PyBaseObject_Type,                /* tp_base */
        0,                                      /* tp_dict */
        0,                                      /* tp_descr_get */
        0,                                      /* tp_descr_set */
        offsetof(instance<>,dict),              /* tp_dictoffset */
        0,                                      /* tp_init */
        PyType_GenericAlloc,                    /* tp_alloc */
        instance_new,                           /* tp_new */
        0,                                      /* tp_free */
        0,                                      /* 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
    };
  
    BOOST_PYTHON_DECL type_handle class_type()
    {
        if (class_type_object.tp_dict == 0)
        {
            Py_TYPE(&class_type_object) = incref(class_metatype().get());
            class_type_object.tp_base = &PyBaseObject_Type;
            if (PyType_Ready(&class_type_object))
                return type_handle();
  //          class_type_object.tp_setattro = class_setattro;
        }
        return type_handle(borrowed(&class_type_object));
    }
  
    BOOST_PYTHON_DECL void*
    find_instance_impl(PyObject* inst, type_info type, bool null_shared_ptr_only)
    {
        if (!Py_TYPE(Py_TYPE(inst)) ||
                !PyType_IsSubtype(Py_TYPE(Py_TYPE(inst)), &class_metatype_object))
            return 0;
      
        instance<>* self = reinterpret_cast<instance<>*>(inst);
  
        for (instance_holder* match = self->objects; match != 0; match = match->next())
        {
            void* const found = match->holds(type, null_shared_ptr_only);
            if (found)
                return found;
        }
        return 0;
    }
  
    object module_prefix()
    {
        return object(
            PyObject_IsInstance(scope().ptr(), upcast<PyObject>(&PyModule_Type))
            ? object(scope().attr("__name__"))
            : api::getattr(scope(), "__module__", str())
            );
    }
  
    namespace
    {
      // Find a registered class object corresponding to id. Return a
      // null handle if no such class is registered.
      inline type_handle query_class(type_info id)
      {
          converter::registration const* p = converter::registry::query(id);
          return type_handle(
              python::borrowed(
                  python::allow_null(p ? p->m_class_object : 0))
              );
      }
  
      // Find a registered class corresponding to id. If not found,
      // throw an appropriate exception.
      type_handle get_class(type_info id)
      {
          type_handle result(query_class(id));
  
          if (result.get() == 0)
          {
              object report("extension class wrapper for base class ");
              report = report + id.name() + " has not been created yet";
              PyErr_SetObject(PyExc_RuntimeError, report.ptr());
              throw_error_already_set();
          }
          return result;
      }
  
      // class_base constructor
      //
      // name -      the name of the new Python class
      //
      // num_types - one more than the number of declared bases
      //
      // types -     array of python::type_info, the first item
      //             corresponding to the class being created, and the
      //             rest corresponding to its declared bases.
      //
      inline object
      new_class(char const* name, std::size_t num_types, type_info const* const types, char const* doc)
      {
        assert(num_types >= 1);
        
        // Build a tuple of the base Python type objects. If no bases
        // were declared, we'll use our class_type() as the single base
        // class.
        ssize_t const num_bases = (std::max)(num_types - 1, static_cast<std::size_t>(1));
        handle<> bases(PyTuple_New(num_bases));
  
        for (ssize_t i = 1; i <= num_bases; ++i)
        {
            type_handle c = (i >= static_cast<ssize_t>(num_types)) ? class_type() : get_class(types[i]);
            // PyTuple_SET_ITEM steals this reference
            PyTuple_SET_ITEM(bases.get(), static_cast<ssize_t>(i - 1), upcast<PyObject>(c.release()));
        }
  
        // Call the class metatype to create a new class
        dict d;
     
        object m = module_prefix();
        if (m) d["__module__"] = m;
  
        if (doc != 0)
            d["__doc__"] = doc;
        
        object result = object(class_metatype())(name, bases, d);
        assert(PyType_IsSubtype(Py_TYPE(result.ptr()), &PyType_Type));
        
        if (scope().ptr() != Py_None)
            scope().attr(name) = result;
  
        // For pickle. Will lead to informative error messages if pickling
        // is not enabled.
        result.attr("__reduce__") = object(make_instance_reduce_function());
  
        return result;
      }
    }
    
    class_base::class_base(
        char const* name, std::size_t num_types, type_info const* const types, char const* doc)
        : object(new_class(name, num_types, types, doc))
    {
        // Insert the new class object in the registry
        converter::registration& converters = const_cast<converter::registration&>(
            converter::registry::lookup(types[0]));
  
        // Class object is leaked, for now
        converters.m_class_object = (PyTypeObject*)incref(this->ptr());
    }
  
    BOOST_PYTHON_DECL void copy_class_object(type_info const& src, type_info const& dst)
    {
        converter::registration& dst_converters
            = const_cast<converter::registration&>(converter::registry::lookup(dst));
        
        converter::registration const& src_converters = converter::registry::lookup(src);
  
        dst_converters.m_class_object = src_converters.m_class_object;
    }
    
    void class_base::set_instance_size(std::size_t instance_size)
    {
        this->attr("__instance_size__") = instance_size;
    }
    
    void class_base::add_property(
      char const* name, object const& fget, char const* docstr)
    {
        object property(
            (python::detail::new_reference)
            PyObject_CallFunction((PyObject*)&PyProperty_Type, const_cast<char*>("Osss"), fget.ptr(), 0, 0, docstr));
        
        this->setattr(name, property);
    }
  
    void class_base::add_property(
      char const* name, object const& fget, object const& fset, char const* docstr)
    {
        object property(
            (python::detail::new_reference)
            PyObject_CallFunction((PyObject*)&PyProperty_Type, const_cast<char*>("OOss"), fget.ptr(), fset.ptr(), 0, docstr));
        
        this->setattr(name, property);
    }
  
    void class_base::add_static_property(char const* name, object const& fget)
    {
        object property(
            (python::detail::new_reference) 
            PyObject_CallFunction(static_data(), const_cast<char*>("O"), fget.ptr())
            );
        
        this->setattr(name, property);
    }
  
    void class_base::add_static_property(char const* name, object const& fget, object const& fset)
    {
        object property(
            (python::detail::new_reference)
            PyObject_CallFunction(static_data(), const_cast<char*>("OO"), fget.ptr(), fset.ptr()));
        
        this->setattr(name, property);
    }
  
    void class_base::setattr(char const* name, object const& x)
    {
        if (PyObject_SetAttrString(this->ptr(), const_cast<char*>(name), x.ptr()) < 0)
            throw_error_already_set();
    }
  
    namespace
    {
      extern "C" PyObject* no_init(PyObject*, PyObject*)
      {
          ::PyErr_SetString(::PyExc_RuntimeError, const_cast<char*>("This class cannot be instantiated from Python"));
          return NULL;
      }
      static ::PyMethodDef no_init_def = {
          const_cast<char*>("__init__"), no_init, METH_VARARGS,
          const_cast<char*>("Raises an exception\n"
                            "This class cannot be instantiated from Python\n")
      };
    }
    
    void class_base::def_no_init()
    {
        handle<> f(::PyCFunction_New(&no_init_def, 0));
        this->setattr("__init__", object(f));
    }
  
    void class_base::enable_pickling_(bool getstate_manages_dict)
    {
        setattr("__safe_for_unpickling__", object(true));
        
        if (getstate_manages_dict)
        {
            setattr("__getstate_manages_dict__", object(true));
        }
    }
  
    namespace
    {
      PyObject* callable_check(PyObject* callable)
      {
          if (PyCallable_Check(expect_non_null(callable)))
              return callable;
  
          ::PyErr_Format(
              PyExc_TypeError
            , const_cast<char*>("staticmethod expects callable object; got an object of type %s, which is not callable")
              , Py_TYPE(callable)->tp_name
              );
          
          throw_error_already_set();
          return 0;
      }
    }
    
    void class_base::make_method_static(const char * method_name)
    {
        PyTypeObject* self = downcast<PyTypeObject>(this->ptr());
        dict d((handle<>(borrowed(self->tp_dict))));
  
        object method(d[method_name]);
  
        this->attr(method_name) = object(
            handle<>(
                PyStaticMethod_New((callable_check)(method.ptr()) )
                ));
    }
  
    BOOST_PYTHON_DECL type_handle registered_class_object(type_info id)
    {
        return query_class(id);
    }
  } // namespace objects
  
  
  void* instance_holder::allocate(PyObject* self_, std::size_t holder_offset, std::size_t holder_size)
  {
      assert(PyType_IsSubtype(Py_TYPE(Py_TYPE(self_)), &class_metatype_object));
      objects::instance<>* self = (objects::instance<>*)self_;
      
      int total_size_needed = holder_offset + holder_size;
      
      if (-Py_SIZE(self) >= total_size_needed)
      {
          // holder_offset should at least point into the variable-sized part
          assert(holder_offset >= offsetof(objects::instance<>,storage));
  
          // Record the fact that the storage is occupied, noting where it starts
          Py_SIZE(self) = holder_offset;
          return (char*)self + holder_offset;
      }
      else
      {
          void* const result = PyMem_Malloc(holder_size);
          if (result == 0)
              throw std::bad_alloc();
          return result;
      }
  }
  
  void instance_holder::deallocate(PyObject* self_, void* storage) throw()
  {
      assert(PyType_IsSubtype(Py_TYPE(Py_TYPE(self_)), &class_metatype_object));
      objects::instance<>* self = (objects::instance<>*)self_;
      if (storage != (char*)self + Py_SIZE(self))
      {
          PyMem_Free(storage);
      }
  }
  
  }} // namespace boost::python
  