diff --git a/build/filemgr.py b/build/filemgr.py index 33e43519..690956db 100644 --- a/build/filemgr.py +++ b/build/filemgr.py @@ -52,8 +52,13 @@ bpl_exa + "/tst_dvect2.py", bpl_exa + "/tst_ivect1.py", bpl_exa + "/tst_ivect2.py", bpl_exa + "/test_cross_module.py", -bpl_exa + "/richcmp.cpp", -bpl_exa + "/test_richcmp.py", +bpl_exa + "/vector_wrapper.h", +bpl_exa + "/richcmp1.cpp", +bpl_exa + "/richcmp2.cpp", +bpl_exa + "/richcmp3.cpp", +bpl_exa + "/tst_richcmp1.py", +bpl_exa + "/tst_richcmp2.py", +bpl_exa + "/tst_richcmp3.py", ) defs = ( @@ -70,7 +75,9 @@ defs = ( "noncopyable_import", "ivect", "dvect", -"richcmp", +"richcmp1", +"richcmp2", +"richcmp3", ) if (__name__ == "__main__"): diff --git a/build/irix_CC.mak b/build/irix_CC.mak index 18a97cc7..3b0badb7 100644 --- a/build/irix_CC.mak +++ b/build/irix_CC.mak @@ -47,7 +47,7 @@ DEPOBJ=$(OBJ) \ pickle1.o pickle2.o pickle3.o \ noncopyable_export.o noncopyable_import.o \ ivect.o dvect.o \ - richcmp.o + richcmp1.o richcmp2.o richcmp3.o .SUFFIXES: .o .cpp @@ -60,7 +60,7 @@ all: libboost_python.a \ pickle1.so pickle2.so pickle3.so \ noncopyable_export.so noncopyable_import.so \ ivect.so dvect.so \ - richcmp.so + richcmp1.so richcmp2.so richcmp3.so libboost_python.a: $(OBJ) rm -f libboost_python.a @@ -107,8 +107,14 @@ ivect.so: $(OBJ) ivect.o dvect.so: $(OBJ) dvect.o $(LD) $(LDOPTS) $(OBJ) $(HIDDEN) dvect.o -o dvect.so -richcmp.so: $(OBJ) richcmp.o - $(LD) $(LDOPTS) $(OBJ) richcmp.o -o richcmp.so +richcmp1.so: $(OBJ) richcmp1.o + $(LD) $(LDOPTS) $(OBJ) richcmp1.o -o richcmp1.so + +richcmp2.so: $(OBJ) richcmp2.o + $(LD) $(LDOPTS) $(OBJ) richcmp2.o -o richcmp2.so + +richcmp3.so: $(OBJ) richcmp3.o + $(LD) $(LDOPTS) $(OBJ) richcmp3.o -o richcmp3.so .cpp.o: $(CPP) $(CPPOPTS) -c $*.cpp @@ -140,7 +146,9 @@ clean: rm -f noncopyable_import.o noncopyable_import.so rm -f ivect.o ivect.so rm -f dvect.o dvect.so - rm -f richcmp.o richcmp.so + rm -f richcmp1.o richcmp1.so + rm -f richcmp2.o richcmp2.so + rm -f richcmp3.o richcmp3.so rm -f so_locations *.pyc rm -rf ii_files diff --git a/build/linux_gcc.mak b/build/linux_gcc.mak index 071fa062..4eae38cf 100644 --- a/build/linux_gcc.mak +++ b/build/linux_gcc.mak @@ -48,7 +48,7 @@ DEPOBJ=$(OBJ) \ pickle1.o pickle2.o pickle3.o \ noncopyable_export.o noncopyable_import.o \ ivect.o dvect.o \ - richcmp.o + richcmp1.o richcmp2.o richcmp3.o .SUFFIXES: .o .cpp @@ -61,7 +61,7 @@ all: libboost_python.a \ pickle1.so pickle2.so pickle3.so \ noncopyable_export.so noncopyable_import.so \ ivect.so dvect.so \ - richcmp.so + richcmp1.so richcmp2.so richcmp3.so libboost_python.a: $(OBJ) rm -f libboost_python.a @@ -108,8 +108,14 @@ ivect.so: $(OBJ) ivect.o dvect.so: $(OBJ) dvect.o $(LD) $(LDOPTS) $(OBJ) $(HIDDEN) dvect.o -o dvect.so -richcmp.so: $(OBJ) richcmp.o - $(LD) $(LDOPTS) $(OBJ) richcmp.o -o richcmp.so +richcmp1.so: $(OBJ) richcmp1.o + $(LD) $(LDOPTS) $(OBJ) richcmp1.o -o richcmp1.so + +richcmp2.so: $(OBJ) richcmp2.o + $(LD) $(LDOPTS) $(OBJ) richcmp2.o -o richcmp2.so + +richcmp3.so: $(OBJ) richcmp3.o + $(LD) $(LDOPTS) $(OBJ) richcmp3.o -o richcmp3.so .cpp.o: $(CPP) $(CPPOPTS) -c $*.cpp @@ -141,7 +147,9 @@ clean: rm -f noncopyable_import.o noncopyable_import.so rm -f ivect.o ivect.so rm -f dvect.o dvect.so - rm -f richcmp.o richcmp.so + rm -f richcmp1.o richcmp1.so + rm -f richcmp2.o richcmp2.so + rm -f richcmp3.o richcmp3.so rm -f so_locations *.pyc softlinks: diff --git a/build/mingw32.mak b/build/mingw32.mak index a553930a..fa22fca6 100644 --- a/build/mingw32.mak +++ b/build/mingw32.mak @@ -63,7 +63,7 @@ all: libboost_python.a \ pickle1.pyd pickle2.pyd pickle3.pyd \ noncopyable_export.pyd noncopyable_import.pyd \ ivect.pyd dvect.pyd \ - richcmp.pyd + richcmp1.pyd richcmp2.pyd richcmp3.pyd libboost_python.a: $(OBJ) del libboost_python.a @@ -150,11 +150,23 @@ dvect.pyd: $(OBJ) dvect.o --def dvect.def \ $(OBJ) dvect.o $(PYLIB) -richcmp.pyd: $(OBJ) richcmp.o +richcmp1.pyd: $(OBJ) richcmp1.o dllwrap $(DLLWRAPOPTS) \ - --dllname richcmp.pyd \ - --def richcmp.def \ - $(OBJ) richcmp.o $(PYLIB) + --dllname richcmp1.pyd \ + --def richcmp1.def \ + $(OBJ) richcmp1.o $(PYLIB) + +richcmp2.pyd: $(OBJ) richcmp2.o + dllwrap $(DLLWRAPOPTS) \ + --dllname richcmp2.pyd \ + --def richcmp2.def \ + $(OBJ) richcmp2.o $(PYLIB) + +richcmp3.pyd: $(OBJ) richcmp3.o + dllwrap $(DLLWRAPOPTS) \ + --dllname richcmp3.pyd \ + --def richcmp3.def \ + $(OBJ) richcmp3.o $(PYLIB) .cpp.o: $(CPP) $(CPPOPTS) -c $*.cpp diff --git a/build/tru64_cxx.mak b/build/tru64_cxx.mak index 88601e64..63251819 100644 --- a/build/tru64_cxx.mak +++ b/build/tru64_cxx.mak @@ -58,7 +58,7 @@ DEPOBJ=$(OBJ) \ pickle1.o pickle2.o pickle3.o \ noncopyable_export.o noncopyable_import.o \ ivect.o dvect.o \ - richcmp.o + richcmp1.o richcmp2.o richcmp3.o .SUFFIXES: .o .cpp @@ -71,7 +71,7 @@ all: libboost_python.a \ pickle1.so pickle2.so pickle3.so \ noncopyable_export.so noncopyable_import.so \ ivect.so dvect.so \ - richcmp.so + richcmp1.so richcmp2.so richcmp3.so libboost_python.a: $(OBJ) rm -f libboost_python.a @@ -122,8 +122,14 @@ ivect.so: $(OBJ) ivect.o dvect.so: $(OBJ) dvect.o $(LD) $(LDOPTS) $(OBJ) $(HIDDEN) dvect.o -o dvect.so -richcmp.so: $(OBJ) richcmp.o - $(LD) $(LDOPTS) $(OBJ) richcmp.o -o richcmp.so +richcmp1.so: $(OBJ) richcmp1.o + $(LD) $(LDOPTS) $(OBJ) richcmp1.o -o richcmp1.so + +richcmp2.so: $(OBJ) richcmp2.o + $(LD) $(LDOPTS) $(OBJ) richcmp2.o -o richcmp2.so + +richcmp3.so: $(OBJ) richcmp3.o + $(LD) $(LDOPTS) $(OBJ) richcmp3.o -o richcmp3.so .cpp.o: $(CPP) $(CPPOPTS) -c $*.cpp @@ -155,7 +161,9 @@ clean: rm -f noncopyable_import.o noncopyable_import.so rm -f ivect.o ivect.so rm -f dvect.o dvect.so - rm -f richcmp.o richcmp.so + rm -f richcmp1.o richcmp1.so + rm -f richcmp2.o richcmp2.so + rm -f richcmp3.o richcmp3.so rm -f so_locations *.pyc rm -rf cxx_repository diff --git a/build/vc60.mak b/build/vc60.mak index be5c99cf..b1718b9a 100644 --- a/build/vc60.mak +++ b/build/vc60.mak @@ -47,7 +47,7 @@ all: boost_python.lib \ pickle1.pyd pickle2.pyd pickle3.pyd \ noncopyable_export.pyd noncopyable_import.pyd \ ivect.pyd dvect.pyd \ - richcmp.pyd + richcmp1.pyd richcmp2.pyd richcmp3.pyd boost_python.lib: $(OBJ) $(LD) -lib /nologo /out:boost_python.lib $(OBJ) @@ -91,8 +91,14 @@ ivect.pyd: $(OBJ) ivect.obj dvect.pyd: $(OBJ) dvect.obj $(LD) $(LDOPTS) $(OBJ) dvect.obj $(PYLIB) /export:initdvect /out:"dvect.pyd" -richcmp.pyd: $(OBJ) richcmp.obj - $(LD) $(LDOPTS) $(OBJ) richcmp.obj $(PYLIB) /export:initrichcmp /out:"richcmp.pyd" +richcmp1.pyd: $(OBJ) richcmp1.obj + $(LD) $(LDOPTS) $(OBJ) richcmp1.obj $(PYLIB) /export:initrichcmp1 /out:"richcmp1.pyd" + +richcmp2.pyd: $(OBJ) richcmp2.obj + $(LD) $(LDOPTS) $(OBJ) richcmp2.obj $(PYLIB) /export:initrichcmp2 /out:"richcmp2.pyd" + +richcmp3.pyd: $(OBJ) richcmp3.obj + $(LD) $(LDOPTS) $(OBJ) richcmp3.obj $(PYLIB) /export:initrichcmp3 /out:"richcmp3.pyd" .cpp.obj: $(CPP) $(CPPOPTS) /c $*.cpp diff --git a/doc/richcmp.html b/doc/richcmp.html new file mode 100644 index 00000000..2590eec8 --- /dev/null +++ b/doc/richcmp.html @@ -0,0 +1,103 @@ + + +Rich Comparisons + +
+ +c++boost.gif (8819 bytes) + +
+

Rich Comparisons

+ +
+In Python versions up to and including Python 2.0, support for +implementing comparisons on user-defined classes and extension types +was quite simple. Classes could implement a __cmp__ method +that was given two instances of a class as arguments, and could only +return 0 if they were equal or +1 or -1 if +they were not. The method could not raise an exception or return +anything other than an integer value. +In Python 2.1, Rich Comparisons were added (see +PEP 207). +Python classes can now individually overload each of the <, <=, +>, >=, ==, and != operations. + +

+For more detailed information, search for "rich comparison" +here. + +

+Boost.Python supports both automatic overloading and manual overloading +of the Rich Comparison operators. The compile-time support is +independent of the Python version that is used when compiling +Boost.Python extension modules. That is, op_lt for example can +always be used, and the C++ operator< will always be bound +to the Python method __lt__. However, the run-time +behavior will depend on the Python version. + +

+With Python versions before 2.1, the Rich Comparison operators will not +be called by Python when any of the six comparison operators +(<, <=, ==, !=, +>, >=) is used in an expression. The only way +to access the corresponding methods is to call them explicitly, e.g. +a.__lt__(b). Only with Python versions 2.1 or higher will +expressions like a < b work as expected. + +

+To support Rich Comparisions, the Python C API was modified between +Python versions 2.0 and 2.1. A new slot was introduced in the +PyTypeObject structure: tp_richcompare. For backwards +compatibility, a flag (Py_TPFLAGS_HAVE_RICHCOMPARE) has to be +set to signal to the Python interpreter that Rich Comparisions are +supported by a particular type. +There is only one flag for all the six comparison operators. +When any of the six operators is wrapped automatically or +manually, Boost.Python will set this flag. Attempts to use comparison +operators at the Python level that are not defined at the C++ level +will then lead to an AttributeError. That is, in general all six +operators should be supplied. Automatically wrapped operators and +manually wrapped operators can be mixed. For example:

+    boost::python::class_builder<code> py_code(this_module, "code");
+
+    py_code.def(boost::python::constructor<>());
+    py_code.def(boost::python::constructor<int>());
+    py_code.def(boost::python::operators<(  boost::python::op_eq
+                                          | boost::python::op_ne)>());
+    py_code.def(NotImplemented, "__lt__");
+    py_code.def(NotImplemented, "__le__");
+    py_code.def(NotImplemented, "__gt__");
+    py_code.def(NotImplemented, "__ge__");
+
+ +NotImplemented is a simple free function:
+  boost::python::ref
+  NotImplemented(const code&, const code&) {
+    return
+    boost::python::ref(Py_NotImplemented, boost::python::ref::increment_count);
+  }
+
+ +See also: + + +
+© Copyright Nicholas K. Sauter & Ralf W. Grosse-Kunstleve 2001. +Permission to copy, use, modify, sell and distribute this document is +granted provided this copyright notice appears in all copies. This +document is provided "as is" without express or implied warranty, and +with no claim as to its suitability for any purpose. + +

+Updated: July 2001 + +

diff --git a/doc/special.html b/doc/special.html index 0caa1924..46ca0791 100644 --- a/doc/special.html +++ b/doc/special.html @@ -60,13 +60,27 @@ __str__(self)
Create a string representation which is suitable for printing. +
+ __lt__(self, other) +
+ __le__(self, other) +
+ __eq__(self, other) +
+ __ne__(self, other) +
+ __gt__(self, other) +
+ __ge__(self, other) +
+ Rich Comparison methods. + New in Python 2.1. + See Rich Comparisons.
__cmp__(self, other)
- Three-way compare function, used to implement comparison operators - (< etc.) Should return a negative integer if self < other - , zero if self == other , a positive integer if - self > other . + Three-way compare function. + See Rich Comparisons.
__hash__(self)
@@ -544,17 +558,42 @@ Note that "__rrpow__" is an extension not present in plain Python. __cmp__, __rcmp__ cmp(left, right)
- left < right
- left <= right
- left > right
- left >= right
- left == right
- left != right +
See Rich Comparisons. op_cmp cpp_left < cpp_right 
cpp_right < cpp_left + + + __lt__ +
__le__ +
__eq__ +
__ne__ +
__gt__ +
__ge__ + + left < right +
left <= right +
left == right +
left != right +
left > right +
left >= right +
See Rich Comparisons + + op_lt +
op_le +
op_eq +
op_ne +
op_gt +
op_ge + + cpp_left < cpp_right  +
cpp_left <= cpp_right  +
cpp_left == cpp_right  +
cpp_left != cpp_right  +
cpp_left > cpp_right  +
cpp_left >= cpp_right  diff --git a/example/richcmp1.cpp b/example/richcmp1.cpp new file mode 100644 index 00000000..c24f25a1 --- /dev/null +++ b/example/richcmp1.cpp @@ -0,0 +1,63 @@ +// Example by Ralf W. Grosse-Kunstleve & Nicholas K. Sauter +// This example shows how to use rich comparisons for a vector type. +// It also shows how to template the entire wrapping of a std::vector. +// See vector_wrapper.h. + +#include +#include "vector_wrapper.h" + +namespace std { + +# define VECTOR_BINARY_OPERATORS(oper) \ + template \ + std::vector \ + operator##oper(const std::vector& a, const std::vector& b) \ + { \ + if (a.size()!=b.size()){throw boost::python::argument_error();} \ + std::vector result(a.size()); \ + for (std::size_t i=0; i) + VECTOR_BINARY_OPERATORS(>=) +# undef VECTOR_BINARY_OPERATORS + +} + +namespace { + + void init_module(boost::python::module_builder& this_module) + { + (void) + example::wrap_vector(this_module, "vector_of_bool", bool()); + + boost::python::class_builder< + std::vector, example::vector_wrapper > + py_vector_of_double = + example::wrap_vector(this_module, "vector_of_double", double()); + + const long comp_operators = + ( boost::python::op_lt | boost::python::op_le + | boost::python::op_eq | boost::python::op_ne + | boost::python::op_gt | boost::python::op_ge); + py_vector_of_double.def(boost::python::operators()); + } + +} // namespace + +BOOST_PYTHON_MODULE_INIT(richcmp1) +{ + try { + boost::python::module_builder this_module("richcmp1"); + // The actual work is done in separate function in order + // to suppress a bogus VC60 warning. + init_module(this_module); + } + catch(...){boost::python::handle_exception();} +} diff --git a/example/richcmp2.cpp b/example/richcmp2.cpp new file mode 100644 index 00000000..ff91a595 --- /dev/null +++ b/example/richcmp2.cpp @@ -0,0 +1,61 @@ +// Example by Ralf W. Grosse-Kunstleve +// This example shows how to use rich comparisons for a type that +// does not support all six operators (<, <=, ==, !=, >, >=). +// To keep the example simple, we are using a "code" type does +// not really require rich comparisons. __cmp__ would be sufficient. +// However, with a more complicated type the main point of this +// example would be in danger of getting lost. + +#include + +namespace { + + // suppose operator< and operator> are not meaningful for code + class code { + public: + code(int c = 0) : m_code(c) {} + inline friend bool operator==(const code& lhs, const code& rhs) { + return lhs.m_code == rhs.m_code; + } + inline friend bool operator!=(const code& lhs, const code& rhs) { + return lhs.m_code != rhs.m_code; + } + private: + int m_code; + }; + + boost::python::ref + NotImplemented(const code&, const code&) { + return + boost::python::ref(Py_NotImplemented, boost::python::ref::increment_count); + } +} + +namespace { + + void init_module(boost::python::module_builder& this_module) + { + boost::python::class_builder py_code(this_module, "code"); + + py_code.def(boost::python::constructor<>()); + py_code.def(boost::python::constructor()); + py_code.def(boost::python::operators<( boost::python::op_eq + | boost::python::op_ne)>()); + py_code.def(NotImplemented, "__lt__"); + py_code.def(NotImplemented, "__le__"); + py_code.def(NotImplemented, "__gt__"); + py_code.def(NotImplemented, "__ge__"); + } + +} // namespace + +BOOST_PYTHON_MODULE_INIT(richcmp2) +{ + try { + boost::python::module_builder this_module("richcmp2"); + // The actual work is done in separate function in order + // to suppress a bogus VC60 warning. + init_module(this_module); + } + catch(...){boost::python::handle_exception();} +} diff --git a/example/richcmp.cpp b/example/richcmp3.cpp old mode 100755 new mode 100644 similarity index 97% rename from example/richcmp.cpp rename to example/richcmp3.cpp index 68479fbb..c0b454c5 --- a/example/richcmp.cpp +++ b/example/richcmp3.cpp @@ -1,3 +1,6 @@ +// Example by Nicholas K. Sauter & Ralf W. Grosse-Kunstleve. +// Comprehensive operator overloading for two vector types and scalars. + #include "dvect.h" #include "ivect.h" #include @@ -236,10 +239,10 @@ namespace { } // namespace -BOOST_PYTHON_MODULE_INIT(richcmp) +BOOST_PYTHON_MODULE_INIT(richcmp3) { try { - boost::python::module_builder this_module("richcmp"); + boost::python::module_builder this_module("richcmp3"); // The actual work is done in separate function in order // to suppress a bogus VC60 warning. init_module(this_module); diff --git a/example/test_richcmp.py b/example/test_richcmp.py deleted file mode 100644 index afea2a76..00000000 --- a/example/test_richcmp.py +++ /dev/null @@ -1,63 +0,0 @@ -import richcmp,sys -global dv,dv2 -dv = richcmp.ivect((1,2,3,4,5)) -print dv.as_tuple() -dv2 = richcmp.dvect((2,-2,3,8,-5)) -print dv2.as_tuple() - -print (dv+dv2).as_tuple() -print (dv+3).as_tuple() -print (3+dv).as_tuple() - -def python_2_1(): - print "\nvect vs. vect Comparisons:" - print (dv < dv2).as_tuple() - print (dv <= dv2).as_tuple() - print (dv == dv2).as_tuple() - print (dv != dv2).as_tuple() - print (dv > dv2).as_tuple() - print (dv >= dv2).as_tuple() - - print "\nvect vs. scalar Comparisons:" - print (dv < 3).as_tuple() - print (dv <= 3).as_tuple() - print (dv == 3).as_tuple() - print (dv != 3).as_tuple() - print (dv > 3).as_tuple() - print (dv >= 3).as_tuple() - - print "\nscalar vs. vect Comparisons:" - print (3 < dv).as_tuple() - print (3 <= dv).as_tuple() - print (3 == dv).as_tuple() - print (3 != dv).as_tuple() - print (3 > dv).as_tuple() - print (3 >= dv).as_tuple() - -def python_pre_2_1(): - print "\nvect vs. vect Comparisons:" - print (dv.__lt__(dv2)).as_tuple() - print (dv.__le__(dv2)).as_tuple() - print (dv.__eq__(dv2)).as_tuple() - print (dv.__ne__(dv2)).as_tuple() - print (dv.__gt__(dv2)).as_tuple() - print (dv.__ge__(dv2)).as_tuple() - - print "\nvect vs. scalar Comparisons:" - print (dv.__lt__(3)).as_tuple() - print (dv.__le__(3)).as_tuple() - print (dv.__eq__(3)).as_tuple() - print (dv.__ne__(3)).as_tuple() - print (dv.__gt__(3)).as_tuple() - print (dv.__ge__(3)).as_tuple() - - print "\nscalar vs. vect Comparisons:" - -if __name__=='__main__': - try: - if sys.version_info[0]>=2 and sys.version_info[1]>=1: - python_2_1() - else: - python_pre_2_1() - except: - python_pre_2_1() diff --git a/example/tst_richcmp1.py b/example/tst_richcmp1.py new file mode 100644 index 00000000..4d1635c0 --- /dev/null +++ b/example/tst_richcmp1.py @@ -0,0 +1,11 @@ +import richcmp1 +d1 = richcmp1.vector_of_double((0, 1, 3, 3, 6, 7)) +d2 = richcmp1.vector_of_double((1, 2, 3, 4, 5, 6)) +print d1.as_tuple() +print d2.as_tuple() +print (d1 < d2).as_tuple() +print (d1 <= d2).as_tuple() +print (d1 == d2).as_tuple() +print (d1 != d2).as_tuple() +print (d1 > d2).as_tuple() +print (d1 >= d2).as_tuple() diff --git a/example/tst_richcmp2.py b/example/tst_richcmp2.py new file mode 100644 index 00000000..77a2ff53 --- /dev/null +++ b/example/tst_richcmp2.py @@ -0,0 +1,14 @@ +import richcmp2 +c1 = richcmp2.code(1) +c2 = richcmp2.code(2) +c3 = richcmp2.code(2) +print c1 == c2 +print c1 != c2 +print c2 == c3 +print c2 != c3 +print c1 < c2 +print c1 <= c2 +print c1 == c2 +print c1 != c2 +print c1 > c2 +print c1 >= c2 diff --git a/example/tst_richcmp3.py b/example/tst_richcmp3.py new file mode 100644 index 00000000..2c13fd19 --- /dev/null +++ b/example/tst_richcmp3.py @@ -0,0 +1,60 @@ +import richcmp3,sys +global iv,dv +iv = richcmp3.ivect((1,2,3,4,5)) +print iv.as_tuple() +dv = richcmp3.dvect((2,-2,3,8,-5)) +print dv.as_tuple() + +print (iv+dv).as_tuple() +print (iv+3).as_tuple() +print (3+iv).as_tuple() + +def python_2_1(): + print "\nvect vs. vect Comparisons:" + print (iv < dv).as_tuple() + print (iv <= dv).as_tuple() + print (iv == dv).as_tuple() + print (iv != dv).as_tuple() + print (iv > dv).as_tuple() + print (iv >= dv).as_tuple() + + print "\nvect vs. scalar Comparisons:" + print (iv < 3).as_tuple() + print (iv <= 3).as_tuple() + print (iv == 3).as_tuple() + print (iv != 3).as_tuple() + print (iv > 3).as_tuple() + print (iv >= 3).as_tuple() + + print "\nscalar vs. vect Comparisons:" + print (3 < iv).as_tuple() + print (3 <= iv).as_tuple() + print (3 == iv).as_tuple() + print (3 != iv).as_tuple() + print (3 > iv).as_tuple() + print (3 >= iv).as_tuple() + +def python_pre_2_1(): + print "\nvect vs. vect Comparisons:" + print (iv.__lt__(dv)).as_tuple() + print (iv.__le__(dv)).as_tuple() + print (iv.__eq__(dv)).as_tuple() + print (iv.__ne__(dv)).as_tuple() + print (iv.__gt__(dv)).as_tuple() + print (iv.__ge__(dv)).as_tuple() + + print "\nvect vs. scalar Comparisons:" + print (iv.__lt__(3)).as_tuple() + print (iv.__le__(3)).as_tuple() + print (iv.__eq__(3)).as_tuple() + print (iv.__ne__(3)).as_tuple() + print (iv.__gt__(3)).as_tuple() + print (iv.__ge__(3)).as_tuple() + + print "\nscalar vs. vect Comparisons:" + +if __name__=='__main__': + if sys.version_info[0]>=2 and sys.version_info[1]>=1: + python_2_1() + else: + python_pre_2_1() diff --git a/example/vector_wrapper.h b/example/vector_wrapper.h new file mode 100644 index 00000000..902e5e33 --- /dev/null +++ b/example/vector_wrapper.h @@ -0,0 +1,117 @@ +// Based on wrapVector.hh by Mike Owen and Jeff Johnson. +// http://cvs.sourceforge.net/cgi-bin/viewcvs.cgi/spheral/src/src/BPLWraps/CXXWraps/ + +#ifndef BOOST_PYTHON_EXAMPLE_VECTOR_WRAPPER_H +#define BOOST_PYTHON_EXAMPLE_VECTOR_WRAPPER_H + +#include + +namespace example { + + // A wrapper is used to define additional constructors. This wrapper + // is templated on the template parameter for its corresponding vector. + template + struct vector_wrapper: std::vector + { + // Tell the compiler how to convert a base class object to + // this wrapper object. + vector_wrapper(PyObject*, + const std::vector& vec): + std::vector(vec) {} + + vector_wrapper(PyObject* self): + std::vector() {} + + vector_wrapper(PyObject* self, + std::size_t n): + std::vector(n) {} + + vector_wrapper(PyObject* self, + boost::python::tuple tuple): + std::vector(tuple.size()) + { + std::vector::iterator vec = begin(); + for (std::size_t i = 0; i < tuple.size(); i++) + vec[i] = BOOST_PYTHON_CONVERSION::from_python(tuple[i].get(), + boost::python::type()); + } + }; + + void raise_vector_IndexError() { + PyErr_SetString(PyExc_IndexError, "vector index out of range"); + throw boost::python::error_already_set(); + } + + template + struct vector_access + { + static + const T + getitem(const std::vector& vec, + const std::size_t key) + { + if (key >= vec.size()) raise_vector_IndexError(); + return vec[key]; + } + + static + void + setitem(std::vector& vec, + const std::size_t key, + const T &value) + { + if (key >= vec.size()) raise_vector_IndexError(); + vec[key] = value; + } + + static + void + delitem(std::vector& vec, + const std::size_t key) + { + if (key >= vec.size()) raise_vector_IndexError(); + vec.erase(vec.begin() + key); + } + + // Convert vector to a regular Python tuple. + static + boost::python::tuple + as_tuple(const std::vector& vec) + { + // Create a python type of size vec.size(). + boost::python::tuple t(vec.size()); + for (std::size_t i = 0; i < vec.size(); i++) { + t.set_item(i, + boost::python::ref(BOOST_PYTHON_CONVERSION::to_python(vec[i]))); + } + return t; + } + }; + + // This function will build a vector and add it to the given + // module with the given name. + template + boost::python::class_builder, vector_wrapper > + wrap_vector(boost::python::module_builder& module, + const std::string& vector_name, + const T&) + { + // Add the vector to the module. + boost::python::class_builder, vector_wrapper > + py_vector(module, vector_name.c_str()); + + // Define constructors and methods for the vector. + py_vector.def(boost::python::constructor<>()); + py_vector.def(boost::python::constructor()); + py_vector.def(boost::python::constructor()); + py_vector.def(&std::vector::size, "__len__"); + py_vector.def(&vector_access::getitem, "__getitem__"); + py_vector.def(&vector_access::setitem, "__setitem__"); + py_vector.def(&vector_access::delitem, "__delitem__"); + py_vector.def(&vector_access::as_tuple, "as_tuple"); + + return py_vector; + } +} + +#endif // BOOST_PYTHON_EXAMPLE_VECTOR_WRAPPER_H diff --git a/src/types.cpp b/src/types.cpp index 88c37b89..f8cf1ea6 100644 --- a/src/types.cpp +++ b/src/types.cpp @@ -457,20 +457,15 @@ void create_method_table_if_null(T*& table) } } -#define ENABLE_RICHCOMPARE_CAPABILITY \ - dest->tp_richcompare = &do_instance_richcompare; \ - dest->tp_flags |= Py_TPFLAGS_HAVE_RICHCOMPARE; \ - return true - bool add_capability_richcompare(type_object_base::capability capability, PyTypeObject* dest) { assert(dest != 0); if (capability == type_object_base::richcompare) { #if PYTHON_API_VERSION >= 1010 - ENABLE_RICHCOMPARE_CAPABILITY; -#else - return true; + dest->tp_richcompare = &do_instance_richcompare; + dest->tp_flags |= Py_TPFLAGS_HAVE_RICHCOMPARE; #endif + return true; } return false;