boost::python, returning new PyObject references

David Abrahams david.abrahams at rcn.com
Mon Jan 7 21:15:18 CET 2002


----- Original Message -----
From: "Arnaldur Gylfason" <arnaldur at decode.is>

> Dave,
>
> It would be great if you could give an example (maybe something that can
> solve object<sequence,mapping>)  so I can see the way.

I don't think we're ready to solve that problem yet, but let me try to
sketch an approach (just a sketch, keep that in mind):

1. Low-level interface components are supplied by type generators
corresponding to fine-grained interface elements. Their constructor contains
the validation code:

struct getattr_generator
{
    template <class T, Base = empty>
    struct type : Base
    {
        void validate()
        {
            T* self = static_cast<T*>(this);
            if (!self->ob_type->tp_getattr && !self->ob_type->tp_getattro)
                throw something;
        }

        // maybe this should return object<>, I don't know.
        ref getattr(char const* name)
        {
            T* self = static_cast<T*>(this);
            return ref(PyObject_GetAttrString(self->get_callback()(),
name));
        }
    };
};

struct indexable_generator
{
    template <class T, Base = empty>
    struct type : Base
    {
        // select the right proxy type
        typedef typename boost::mpl::select_type<
            is_mutable<T>::value
            , mutable_proxy
            , const_proxy>::type proxy;

        // implement operator[] for T
        template <class U>
        proxy operator[](U const& index_)
        {
            ref index(to_python(index_));
            T* self = static_cast<T*>(this);

            return proxy(some_expression(self->get_callback(),
self->set_callback(), ref));
        }

        void validate()
        {
            T* self = static_cast<T*>(this);
            if
(!self->get_callback()()->ob_type->tp_as_sequence->tp_getitem)
                throw something;
        }
    };
};

Concepts such as sequence may correspond to a type_list of these generators.
In the case of sequence, I don't think there's anything more than indexable:

struct sequence : mpl::type_list<indexable_generator> {};
struct integral :
mpl::type_list<addable_generator,subtractable_generator,...> {};

then we can define object<c1,c2,c3...cn> as:

template <class....>
struct object
    : gen_linear_hierarchy<
        typename get_unique_generators<mpl::type_list<c1,c2...cn> >::type
    , use_generator<
            object<c1,c2,c3...cn>
        >
    >
{
};

where use_generator is something like:

template <class Object>
struct use_generator
{
    template <class Generator, class Base>
    struct apply
    {
        typedef Generator::template type<Object, Base> type;
    };
};

and where get_unique_generators is something like:

struct all_generators : mpl::type_list<
        indexable_generator,getattr_generator, setattr_generator...>
{};

template <class ConceptList>
struct get_unique_generators
{
    typedef typename mpl::copy_if<all_generators, in_a_sublist<ConceptList>
>::type type;
};

and in_a_sublist is:

template <class ListOfLists>
struct in_a_sublist
{
    template <class T>
    struct apply
    {
        BOOST_STATIC_CONSTANT(bool, value =
            // an expression which is true iff T is in any
            // of the Lists contained in ListOfLists
    };
};

Whew, I'm tired now! This is pretty complicated; Perhaps it can be
simplified.

> I have only taken a brief look at 2 files in boost::mpl but am interested
> in exploring this kind of programming.

It's a lot of fun. Take a look at the example and test directories also for
some illuminating samples.





More information about the Cplusplus-sig mailing list