From klm at python.org Tue Mar 17 03:17:05 1998 From: klm at python.org (Ken Manheimer) Date: Mon, 16 Mar 1998 21:17:05 -0500 (EST) Subject: [C++-SIG] Testing transition to mailman list processor Message-ID: <199803170217.VAA11762@glyph.CNRI.Reston.Va.US> The C++-SIG mailing list has just been migrated to mailman, a python-based maillist management system. All subscribers should have received a "welcome" message informing you about how to access their membership account. In summary, the crucial piece of information is to visit: http://www.python.org/mailman/listinfo/objc-sig for the introductory page. You should be able to find your account from there. In any case, postings to the maillist itself should work pretty much as they did before. If you have questions, feel free to contact me or your list manager, geoffrey furnish, furnish at lanl.gov... Thanks! Ken Manheimer klm at python.org 703 620-8990 x268 (orporation for National Research |nitiatives # If you appreciate Python, consider joining the PSA! # # . # From ulli at egd.igd.fhg.de Thu Mar 19 14:38:14 1998 From: ulli at egd.igd.fhg.de (Ullrich Koethe) Date: Thu, 19 Mar 1998 14:38:14 +0100 Subject: [C++-SIG] Automatic Python/C++ Wrapper Message-ID: <35111FC6.1CFB@egd.igd.fhg.de> Hi Everybody, since I would like to use Python as a high level control language in a C++ project, I'm interested in a simple way to wrap C++ objects into Python objects. However, the existing solutions (like SWIG) seem to be rather complicated. So I implemented an new tool 'Python', which is inlcuded below. Unlike previous approaches, my tool makes use of templates to automate the generation of wrapper objects. This allows to: - keep the entire wrapping tool in just 3 header files (no library or code generator required) - keep the C++ code essentially independent of Python (no inheritance from PyObject or similar required) Suppose, you want to wrap this function: double foo(double, double); To wrap it, you simply write: pyWrapFunction(foo, foo); where the first argument will become the Python identifier of the function, while the second is a pointer to the C++ function. In Python, you would call the function like this: >>> foo(1.0, 2.0) Likewise, a class class Foo { public: Foo(); virtual ~Foo(); virtual int foo_method(int, int); }; is wrapped as follows: pyWrapClass(Foo, Foo); where the first argument is the Python class name, the second the C++ class name. Methods are wrapped similarly to functions: pyWrapMethod(Foo, bar, &Foo::foo_method); whith the first two arguments being the Python class and method names, and the last a pointer to a C++ member function. To wrap constructors, the argument list is given instead of a function pointer (pointers to constructors do not exist in C++): pyWrapDefaultConstructor(Foo, Foo); We use class Foo in Python like this: >>> x = Foo() >>> x.foo_method(1,2); >>> del x Inheritance is also supported: class Bar : public Foo {}; pyWrapClass(Bar, Bar); pyDeclareBaseClass(Bar, Foo); pyWrapDefaultConstructor(Bar, Bar); Thus, the Python class Bar is declared a subclass of the Python class Foo - it inherits all methods and is convertible into a base object in an expression. (This code only compiles iff the C++ class Bar is indeed a direct or indirect subclass of the C++ class Foo). In Python, we use Bar like this: >>> x = Bar() >>> x.foo_method(1,2); # inherited from Foo >>> del x Other features of 'Python' include support for multiple inheritance, virtual base classes, abstract classes, translation of C++ exceptions into Python exceptions, mapping of Python tuples (up to 5 members) and (homogeneous) lists onto PyWrapperTuple and PyWrapperArray. The module 'cxxmodule.cxx' included in the tar file illustrates some of these features (sorry, no documentation exists yet). I have successfully compiled and used the module under Python 1.5, GNU g++ 2.8.0, on a UNIX machine. The script 'test.py' is provided to test the module. The expected output is contained in 'testout.txt'. To try: g++ -fpic -I$PYTHON_INCLUDE -c cxxmodule.cxx -o cxxmodule.o g++ -shared -o cxxmodule.so cxxmodule.o python test.py >& out.txt diff out.txt testout.txt I hope you enjoy the package. Any comments are very welcome. Regards, Ulli -- _____________________________________________________________ | | | Ullrich Koethe Fraunhofer Institute for Computer Graphics | | Rostock | | | | Phone: +49-381-4024-114 Joachim-Jungius-Str. 9 | | Fax: +49-381-4024-199 D - 18059 Rostock | | Email: koethe at egd.igd.fhg.de Germany | |_____________________________________________________________| -------------- next part -------------- A non-text attachment was scrubbed... Name: pythoncplusplus.tar.gz Type: x-world/x-vrml Size: 14441 bytes Desc: not available URL: From patmiller at llnl.gov Thu Mar 19 17:21:00 1998 From: patmiller at llnl.gov (Patrick Miller) Date: Thu, 19 Mar 1998 08:21:00 -0800 Subject: [C++-SIG] Automatic Python/C++ Wrapper References: <35111FC6.1CFB@egd.igd.fhg.de> Message-ID: <351145EC.469CC2B2@llnl.gov> > - keep the entire wrapping tool in just 3 header files (no library > or code generator required) > - keep the C++ code essentially independent of Python (no inheritance > from PyObject or similar required) At LLNL, we are using a home grown "bridge language" to glue the two pieces together. We too want to keep the C++ looking and acting like C++, but have the python looking and acting like python. Here's what we do in the header file (your class with some additions to show other features) class Foo { public: Foo(); Foo(int); virtual ~Foo(); virtual int foo_method(int, int); int getX(); void setX(int); }; class Bar : public Foo { public: Bar(); Bar(int,int); int getY(); void setY(int); }; class FooBar { public: FooBar(Foo&,Bar&); }; /*#!python wrapper('Foo', '#include "Foo.h"', ctor(), ctor(int), mfunc('void','foo_method(int,int)'), mfunc('void','foo_method(int,int,char*)'), attr('int','x','@->getX()','@->setX($1)',doc='an x attr'), doc='A foo is half of a foobar'), wrapper('Bar', inherit('Foo'), ctor(), ctor('int','int'), attr('int','y','@->getY()','@->setY($1)'), doc='A bar is half of a foobar'), ), wrapper('FooBar', ctor('Foo&','Bar&') ) */ We run our PYFFLE script over it to create method.cc and a foomodule.c file for the extensions. >>> from foo import Foo,Bar,FooBar # These are FUNCTIONS that create >>> # the new types >>> f = foo() >>> print f # The default string method can be overriden >>> print f.x 0 >>> f.x = 3 >>> f.foo_method() ValueError: needs 2 or 3 arguments >>> f.foo_method(1,2) I'm in foo_method >>> b = Bar() >>> b.foo_method(1,2) I'm in foo_method >>> fb = FooBar(f,b) ----------------------------------------------- PYFFLE has other features too like building python sequence types (add a __len__ mfunc and a seq('kfsdkf','[int]', , ) line to any PYFFLE wrapper), We also build and use a lot of STL containers, so we have support for vector and list. PYFFLE also will "build on the fly" to support type coercion. For instance, we have a class "Triplet" which is a triple of doubles. However, we don't want users to have to do things like wrapper('Take2Triples',ctor('Triplet&','Triplet&'),....) >>> F = Take2Triples(Triplet(1,2,3),Triplet(1,2,3)) when >>> F = Take2Triples((1,2,3),(1,2,3)) reads so much better! So we have added a "contstructable" flag to PYFFLE that allows either the "correct" type to be at an argument site OR something from which the correct type can be built. This is real nice for things that take vector arguments because we can arrange to allow ANY python sequence (something that supports integer __getitem__ and __len__) to be used directly >>> class myseq: def __init__(self,x): pass def __len__(self): return 3 def __getitem__(self,i): return 5 >>> v = F([1,2,3,4]) >>> w = F(range(0,100)) >>> z = F(myseq('abc')) instead of >>> v = F(vector_of_int(1,2,3,4)) >>> w = F(vector_of_int(tuple(range(0,100))) >>> ms = myseq('abc') >>> z = F(vector_of_int(lambda x,i: x[i],ms,range(0,len(ms))) Is there general interest in this? I am hoping to clean it up enough to put on the Starship Pat From dubois1 at llnl.gov Thu Mar 26 18:30:11 1998 From: dubois1 at llnl.gov (Paul F. Dubois) Date: Thu, 26 Mar 1998 09:30:11 -0800 Subject: [C++-SIG] [Announce] CXX Alpha 2 Message-ID: <001c01bd58dc$d4bdcd60$998a7380@pduboispc> 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 using std::ostrstream; using namespace CXX; // Making an extension object extern void init_rtype(); extern PyObject* r_new(PyObject*,PyObject*); class r: public PythonExtension { 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 { public: explicit R (PyObject *pyob): SeqBase(pyob) { validate(); } explicit R (long start, long stop, long step = 1) :SeqBase(FromAPI(new r(start,stop, step))) {} R(const R& other): SeqBase(*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(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 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 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 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."; } From dubois1 at llnl.gov Fri Mar 27 17:48:50 1998 From: dubois1 at llnl.gov (Paul F. Dubois) Date: Fri, 27 Mar 1998 08:48:50 -0800 Subject: [C++-SIG] [Announce] CXX Alpha 2 Message-ID: <003401bd59a0$38b3f880$998a7380@pduboispc> > >I wanted to let you know that I have developed a Python extension >package using the same "curiosly recursive template" pattern. >Perhaps it is worth comparing notes? Obviously. I'm anxious to see your code. The part I can see has some interesting differences. I knew that using member template functions was not going to fly except with a few compilers. We have KCC (Kuck and Associates) on our Unix box, which is slow to compile, quick to run, and very close to the standard. Is your "latest SGI compiler" from SGI? If so maybe we ought to get it. My stuff didn't work with egcs but maybe yours would. I used namespaces and lots of the STL. > >There are two techniques that I used that take advantage of the >recursive template pattern. The first is automatic management >of reference-counted objects, so that your C++ application can use >the objects in a reference-counted way (using smart pointers), and >also interchange the objects with Python code. There is nothing >too magical about this. Well, for the basics, no. But maybe you'll like what I've done. In particular, I have put in enough machinery that you can use STL algorithms on Python containers. If PyObject* p points to a Python list, for example, you can do: List mylist(p); sort(mylist); for(List::iterator j = mylist.begin(); j != mylist.end(); ++j) { do_something_to_the_element (*j); } Also stuff like Dict m; m["hello"] = "world"; >The second trick is to handle automatic >argument conversion for member functions. This is the part that >breaks the compiler :-). Geoff Furnish has also worked on and off on a scheme to allow direct calling of member functions. I didn't try to do any of that because he is working on it. You stuff looks interestingly different. I'm sure we'd both like to study it. >A pass-by-value extension class looks like: > >class MRTest : public Scripting::ValueBase< MRTest > >{ >public: > MRTest( ) { } > MRTest Create( ); > > static void SetupScripting( ) > { > RegisterClassName( "MRTest" ); > > GlobalRegistry::Register( "MRTest", Create ); > > RegisterMember( "Func0", Func0 ); > RegisterMember( "Func1", Func1 ); > RegisterMember( "Func2", Func2 ); > RegisterMember( "Func3", Func3 ); > RegisterMember( "Func4", Func4 ); > } > > const char * Func0( ); > int Func1( int a ); > double Func2( int a, double b ); > MRTest Func3( int a, int b, int c ); > MRTest const & Func4( double a, int b, char const * c, int d ); >}; > >Unfortunately, I stretched the compiler a bit too far. When I start >building real test cases, the Visual C++ 5.0sp3 compiler crashes :-). >The lack of out-of-line templates and proper handling of template >members of template classes also cause trouble, so that the code >becomes very ugly. The most recent SGI compiler is great for all >of this, but obviously doesn't do much good for Windows development. > >Regards, >Garth A. Dickie > I hope you can pick up my distribution at ftp-icf.llnl.gov/pub/python/CXX-2a.zip and (a) see if it works with your SGI compiler, and (b) let me know what you think of it. I worked about 80% of the effort on the CXX_Objects.h file; the CXX_Extensions.h I view as purely a first attempt and I would be glad to merge with something better from you and/or Geoff. CXX_Objects does not depend on the extension stuff. The start of my documentation, which covers class Object at least, is at http://xfiles.llnl.gov. The basic philosophy is that an Object owns a reference to the PyObject* it contains.