[C++-SIG] [Announce] CXX Alpha 2

Paul F. Dubois dubois1 at llnl.gov
Thu Mar 26 18:30:11 CET 1998


On ftp-icf.llnl.gov/pub/python/CXX-2a.zip is a Windows zip file containing
CXX Alpha 2.

CXX is a facility for writing Python extensions in C++. While I have begun
the documentation at http://xfiles.llnl.gov, I have thus far only documented
a minor fraction of the package. However, the Demo directory (which is also
the tester) contains an example of a module extension (example.cxx) and an
extension object (r.h, r.cxx, rtest.cxx).  A Setup file is included at the
top level, and as with NumPy you can run makethis.py to create Windows
project files.

I have tested this package under Windows using Microsoft Visual C++ 5.0 +
Service Patch 3. It is known NOT to work without at least Service Pack 2. I
have compiled the package fairly recently using KCC on a HPUX-10 system but
it doesn't work as a dynamic package. We have used a fairly recent version
in a static application on an SGI system.

The package is known not to work with any compiler that does not support
namespaces.

In short, the package is known not to work a lot more ways than it is known
to work.

As a sampler, here is the header file definition of an extension object.
This is the most experimental part of the package at the moment. And yes,
that is not a misprint: r inherits from something templated on itself. Scott
Meyers told me he calls this the "Curiously Recusive Template Pattern" or
something like that. (The class R that follows is not necessary; it is
essentially a type-safe smart pointer to an "r" object. In this case I am
also giving the object a sequence behavior).

#ifndef __r__h
#define __r__h
#include "CXX_Extensions.h"

#include <strstream>
using std::ostrstream;
using namespace CXX;

// Making an extension object
extern void init_rtype();
extern PyObject* r_new(PyObject*,PyObject*);

class r: public PythonExtension<r> {
public:
    long start;
    long stop;
    long step;
    r(long start_, long stop_, long step_ = 1L) {
        start = start_;
        stop = stop_;
        step = step_;
    }
    long length() const {
        return (stop - start + 1)/step;
    }
    long item(int i) const {
        return start + i * step;
    }
    r* slice(int i, int j) const {
        int first = start + i * step;
        int last = start + j * step;
        return new r(first, last, step);
    }

    r* extend(int k) const {
        return new r(start, stop + k, step);
    }

    std::string asString() const {
        ostrstream s;
        s << "r(" << start << ", " << stop << ", " << step << ")" <<
std::ends;
        return std::string(s.str());
    }
};

class R: public SeqBase<Int> {
public:

    explicit R (PyObject *pyob): SeqBase<Int>(pyob) {
        validate();
    }

    explicit R (long start, long stop, long step = 1)
        :SeqBase<Int>(FromAPI(new r(start,stop, step))) {}

    R(const R& other): SeqBase<Int>(*other) {
        validate();
    }

    R& operator= (const Object& rhs) {
        return (*this = *rhs);
    }

    R& operator= (PyObject* rhsp) {
        if(ptr() == rhsp) return *this;
        set(rhsp);
        return *this;
    }

    virtual bool accepts(PyObject *pyob) {
        return pyob && r::check(pyob);
    }

};
#endif

And here is r.cxx that contains the connection to Python.

#include "r.h"
// Connect r objects to Python

PyObject*
r_new (PyObject* self, PyObject* args) {
    try {
        Tuple rargs(args);
        if (rargs.length() < 2 || rargs.length() > 3) {
            throw PyException_RuntimeError("Incorrect # of args to
r(start,stop [,step]).");
        }
        Int start(rargs[0]);
        Int stop(rargs[1]);
        Int step(1);
        if (rargs.length() == 3) {
            step = rargs[2];
        }
        if (long(start) > long(stop) + 1 || long(step) == 0) {
            throw PyException_RuntimeError("Bad arguments to r(start,stop
[,step]).");
        }
        return new r(start, stop, step);
    }
    catch(const PyException&) {
        return Py_Null;
    }
}

static PyObject *
r_repr(r *robj)
{
 return new_reference_to(String(robj->asString()));
}

static int
r_length(r* robj)
{
    return robj->length();
}

static PyObject*
r_item(r* robj, int i)
{
    return new_reference_to(Int(robj->item(i)));
}

static PyObject*
r_concat(r* robj, PyObject *j) {
    Int k(j);
    return robj->extend(int(k));
}

static PyObject*
r_slice(r* robj, int i, int j) {
    return robj->slice(i,j);
}

static PyObject *
r_getattr(r* robj, char *name)
{
    static MethodTable rmethods;
    if(std::string(name) == "c") return new_reference_to(Float(300.0));
    return Py_FindMethod(rmethods.table(), static_cast<PyObject*>(robj),
name);
}

void init_rtype () {
        r::methods().name("r");
        r::methods().doc("r objects: start, stop, step");
        r::methods().repr(r_repr);
        r::methods().sequence_length(r_length);
        r::methods().item(r_item);
        r::methods().slice(r_slice);
        r::methods().concat(r_concat);
        r::methods().getattr(r_getattr);
}

And finally, here is the test routine rtest.cxx. The class
ExtensionObject<r> is an automatically available class that is a type-safe
smart container of an "r", so that one can create something to hold an "r"
and keep the reference count right without going to the trouble of writing
something like R above. (I know, I've lost you...I'm typing the
documentation as fast as I can, sorry). The part below that where we use R
is more interesting. r::check() supplies the usual PySomething_Check you
usually have to write. Note that r inherited an operator new from
PythonExtension<r> that calls PyObject_NEW to initialize the object, so it
is all kosher.

#include "CXX_Extensions.h"
#include "r.h"
std::string test_extension_object()

        Tuple a; // just something that isn't an r...
        ExtensionObject<r> r1(FromAPI(new r(1,10,2)));
        if(r::check(a)) {
            std::cout << "r::check failed (1).";
        }
        if(!r::check(r1)) {
            return "r::check failed (2).";
        }

        R r2(1, 10, 2);
        if(r2[1] != Int(3)) {
            return "R check failed. ";
        }
        return "ok.";
}





More information about the Cplusplus-sig mailing list