mirror of
https://github.com/boostorg/python.git
synced 2026-01-20 04:42:28 +00:00
added class wrapping
[SVN r12384]
This commit is contained in:
@@ -6,16 +6,44 @@
|
||||
#ifndef CLASS_DWA20011214_HPP
|
||||
# define CLASS_DWA20011214_HPP
|
||||
|
||||
# include <boost/python/module.hpp>
|
||||
# include <boost/python/detail/wrap_python.hpp>
|
||||
# include <boost/python/detail/config.hpp>
|
||||
# include <boost/utility.hpp>
|
||||
# include <boost/python/converter/type_id.hpp>
|
||||
# include <boost/python/reference.hpp>
|
||||
# include <boost/iterator_adaptors.hpp>
|
||||
# include <cstddef>
|
||||
|
||||
namespace boost { namespace python { namespace objects {
|
||||
namespace boost { namespace python {
|
||||
|
||||
class module;
|
||||
|
||||
namespace objects {
|
||||
|
||||
template <class T> struct holder;
|
||||
|
||||
// To identify a class, we don't need cv/reference decorations
|
||||
typedef converter::undecorated_type_id_t class_id;
|
||||
|
||||
struct BOOST_PYTHON_DECL class_base : noncopyable
|
||||
{
|
||||
// constructor
|
||||
class_base(
|
||||
module& name_space // Which name space the class will live in
|
||||
, char const* name // The name of the class
|
||||
|
||||
, std::size_t num_types // A list of class_ids. The first is the type
|
||||
, class_id const*const types // this is wrapping. The rest are the types of
|
||||
// any bases.
|
||||
);
|
||||
|
||||
// Retrieve a pointer to the underlying object
|
||||
PyObject* object() const { return m_object.get(); }
|
||||
private:
|
||||
ref m_object;
|
||||
};
|
||||
|
||||
// Base class for all holders
|
||||
struct BOOST_PYTHON_DECL instance_holder : noncopyable
|
||||
{
|
||||
@@ -28,7 +56,7 @@ struct BOOST_PYTHON_DECL instance_holder : noncopyable
|
||||
|
||||
virtual void* holds(converter::type_id_t) = 0;
|
||||
|
||||
void install(PyObject* inst);
|
||||
void install(PyObject* inst) throw();
|
||||
|
||||
struct iterator_policies : default_iterator_policies
|
||||
{
|
||||
@@ -58,6 +86,8 @@ struct instance
|
||||
instance_holder* objects;
|
||||
};
|
||||
|
||||
// Given a type_id, find the instance data which corresponds to it, or
|
||||
// return 0 in case no such type is held.
|
||||
BOOST_PYTHON_DECL void* find_instance_impl(PyObject*, converter::type_id_t);
|
||||
|
||||
template <class T>
|
||||
@@ -66,8 +96,8 @@ T* find_instance(PyObject* p, T* = 0)
|
||||
return static_cast<T*>(find_instance_impl(p, converter::type_id<T>()));
|
||||
}
|
||||
|
||||
BOOST_PYTHON_DECL PyTypeObject* class_metatype();
|
||||
BOOST_PYTHON_DECL PyTypeObject* class_type();
|
||||
BOOST_PYTHON_DECL ref class_metatype();
|
||||
BOOST_PYTHON_DECL ref class_type();
|
||||
|
||||
//
|
||||
// implementation
|
||||
|
||||
@@ -18,14 +18,14 @@ struct class_unwrapper
|
||||
template <class Target>
|
||||
struct reference_unwrapper : converter::unwrapper<Target>
|
||||
{
|
||||
bool convertible(PyObject* p) const
|
||||
void* can_convert(PyObject* p) const
|
||||
{
|
||||
return find_holder<T>(p) != 0;
|
||||
return find_instance<T>(p);
|
||||
}
|
||||
|
||||
Target convert(PyObject* p, void*&) const
|
||||
Target convert(PyObject* p, void* data, ) const
|
||||
{
|
||||
return *find_holder<T>(p)->target();
|
||||
return *find_instance<T>(p)->target();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -22,10 +22,16 @@ struct BOOST_PYTHON_DECL function : PyObject
|
||||
~function();
|
||||
|
||||
PyObject* call(PyObject*, PyObject*) const;
|
||||
void add_overload(function* overload);
|
||||
|
||||
// Add an attributeto the name_space with the given name. If it is
|
||||
// a function object (this class), and an existing function is
|
||||
// already there, add it as an overload.
|
||||
static void add_to_namespace(
|
||||
PyObject* name_space, char const* name, PyObject* attribute);
|
||||
|
||||
private: // helper functions
|
||||
void argument_error(PyObject* args, PyObject* keywords) const;
|
||||
void add_overload(function* overload);
|
||||
|
||||
private: // data members
|
||||
py_function m_fn;
|
||||
|
||||
@@ -8,6 +8,8 @@
|
||||
|
||||
# include <boost/python/object/class.hpp>
|
||||
# include <boost/python/converter/type_id.hpp>
|
||||
# include <boost/python/object/inheritance.hpp>
|
||||
# include <boost/ref.hpp>
|
||||
|
||||
namespace boost { namespace python { namespace objects {
|
||||
|
||||
@@ -76,9 +78,11 @@ struct value_holder_generator
|
||||
};
|
||||
|
||||
template <class Held>
|
||||
void* value_holder<Held>::holds(converter::type_id_t x)
|
||||
void* value_holder<Held>::holds(converter::type_id_t dst_t)
|
||||
{
|
||||
return x == converter::type_id<Held>() ? &m_held : 0;
|
||||
converter::type_id_t src_t = converter::type_id<Held>();
|
||||
return src_t == dst_t ? &m_held
|
||||
: find_static_type(&m_held, src_t, dst_t);
|
||||
}
|
||||
|
||||
}}} // namespace boost::python::objects
|
||||
|
||||
@@ -6,8 +6,14 @@
|
||||
#include <boost/python/detail/config.hpp>
|
||||
#include <boost/python/detail/wrap_python.hpp>
|
||||
#include <boost/python/object/class.hpp>
|
||||
#include <boost/python/object/class_wrapper.hpp>
|
||||
#include <boost/python/objects.hpp>
|
||||
#include <boost/python/detail/map_entry.hpp>
|
||||
#include <boost/detail/binary_search.hpp>
|
||||
#include <boost/bind.hpp>
|
||||
#include <boost/python/detail/wrap_python.hpp>
|
||||
#include <functional>
|
||||
#include <vector>
|
||||
|
||||
namespace boost { namespace python { namespace objects {
|
||||
|
||||
@@ -64,6 +70,20 @@ PyTypeObject class_metatype_object = {
|
||||
// PyType_GenericNew /* tp_new */
|
||||
};
|
||||
|
||||
// Get the metatype object for all extension classes.
|
||||
BOOST_PYTHON_DECL ref 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 ref();
|
||||
}
|
||||
return ref((PyObject*)&class_metatype_object, ref::increment_count);
|
||||
}
|
||||
|
||||
// Do we really need this? I'm beginning to think we don't!
|
||||
PyTypeObject class_type_object = {
|
||||
PyObject_HEAD_INIT(0) //&class_metatype_object)
|
||||
0,
|
||||
@@ -107,33 +127,21 @@ PyTypeObject class_type_object = {
|
||||
PyType_GenericNew
|
||||
};
|
||||
|
||||
BOOST_PYTHON_DECL PyTypeObject* 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 0;
|
||||
}
|
||||
Py_INCREF(&class_metatype_object);
|
||||
return &class_metatype_object;
|
||||
}
|
||||
|
||||
BOOST_PYTHON_DECL PyTypeObject* class_type()
|
||||
BOOST_PYTHON_DECL ref class_type()
|
||||
{
|
||||
if (class_type_object.tp_dict == 0)
|
||||
{
|
||||
class_type_object.ob_type = class_metatype();
|
||||
class_type_object.ob_type = (PyTypeObject*)class_metatype().release();
|
||||
class_type_object.tp_base = &PyBaseObject_Type;
|
||||
if (PyType_Ready(&class_type_object))
|
||||
return 0;
|
||||
return ref();
|
||||
}
|
||||
Py_INCREF(&class_type_object);
|
||||
return &class_type_object;
|
||||
return ref((PyObject*)&class_type_object, ref::increment_count);
|
||||
}
|
||||
|
||||
void instance_holder::install(PyObject* self)
|
||||
// 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 = ((instance*)self)->objects;
|
||||
@@ -157,4 +165,76 @@ find_instance_impl(PyObject* inst, converter::type_id_t type)
|
||||
return 0;
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
struct class_registry
|
||||
{
|
||||
public:
|
||||
ref get(class_id id) const;
|
||||
void set(class_id, ref class_object);
|
||||
private:
|
||||
typedef detail::map_entry<class_id,ref> entry;
|
||||
std::vector<entry> m_impl;
|
||||
};
|
||||
|
||||
class_registry& registry()
|
||||
{
|
||||
static class_registry x;
|
||||
return x;
|
||||
}
|
||||
|
||||
ref class_registry::get(class_id id) const
|
||||
{
|
||||
std::vector<entry>::const_iterator start = m_impl.begin();
|
||||
std::vector<entry>::const_iterator finish = m_impl.end();
|
||||
|
||||
std::vector<entry>::const_iterator p
|
||||
= boost::detail::lower_bound(start, finish, id);
|
||||
|
||||
if (p == finish && p->key != id)
|
||||
{
|
||||
string report("extension class wrapper for base class ");
|
||||
(report += id.name()) += "has not been created yet";
|
||||
PyErr_SetObject(PyExc_RuntimeError, report.get());
|
||||
throw error_already_set();
|
||||
}
|
||||
return p->value;
|
||||
}
|
||||
|
||||
void class_registry::set(class_id id, ref object)
|
||||
{
|
||||
std::vector<entry>::iterator start = m_impl.begin();
|
||||
std::vector<entry>::iterator finish = m_impl.end();
|
||||
m_impl.insert(
|
||||
boost::detail::lower_bound(start, finish, id)
|
||||
, entry(id, object));
|
||||
}
|
||||
}
|
||||
|
||||
class_base::class_base(
|
||||
module& m, char const* name, std::size_t num_types, class_id const* const types)
|
||||
{
|
||||
class_registry& r = registry();
|
||||
assert(num_types >= 1);
|
||||
tuple bases(std::max(num_types - 1, static_cast<std::size_t>(1)));
|
||||
if (num_types > 1)
|
||||
{
|
||||
for (std::size_t i = 1; i < num_types; ++i)
|
||||
bases.set_item(i - 1, r.get(types[i]));
|
||||
}
|
||||
else
|
||||
{
|
||||
bases.set_item(0, class_type());
|
||||
}
|
||||
|
||||
tuple args(3);
|
||||
args.set_item(0, string(name).reference());
|
||||
args.set_item(1, bases.reference());
|
||||
args.set_item(2, dictionary().reference());
|
||||
|
||||
m_object = ref(PyObject_CallObject(class_metatype().get(), args.get()));
|
||||
r.set(types[0], m_object);
|
||||
m.add(m_object, name);
|
||||
}
|
||||
|
||||
}}} // namespace boost::python::objects
|
||||
|
||||
Reference in New Issue
Block a user