diff --git a/comparisons.html b/comparisons.html
index 565e8bad..d2cabc62 100644
--- a/comparisons.html
+++ b/comparisons.html
@@ -149,9 +149,8 @@
Acquisition.
Zope's ComputedAttribute support is designed to be used from Python.
- The analogous feature of py_cp is designed to be used from C++ (I
- make no claims that the py_cpp mechanism is more useful than the Zope
- mechanism in this case)
+ The analogous feature of py_cpp can be used from C++ or Python. The
+ feature is arguably easier to use in py_cpp.
Also, the Zope docs say: "The first superclass listed in the class
diff --git a/extclass.cpp b/extclass.cpp
index 28651eb8..5c8b44b5 100644
--- a/extclass.cpp
+++ b/extclass.cpp
@@ -239,43 +239,44 @@ ExtensionClassBase::ExtensionClassBase(const char* name)
of the held object to 'T *' is allowed when the conversion
'dynamic_cast *>(an_instance_holder_base)' succeeds.
*/
-void * ExtensionClassBase::try_class_conversions(InstanceHolderBase * object) const
+void * ExtensionClassBase::try_class_conversions(InstanceHolderBase* object) const
{
- void * result = try_derived_class_conversions(object);
+ void* result = try_derived_class_conversions(object);
if(result)
return result;
- result = try_base_class_conversions(object);
- return result;
+
+ return try_base_class_conversions(object);
}
-void * ExtensionClassBase::try_base_class_conversions(InstanceHolderBase * object) const
+void* ExtensionClassBase::try_base_class_conversions(InstanceHolderBase* object) const
{
- void * result = 0;
- for(int i=0; iconvert_from_holder(object);
- if(result)
- return (*base_classes()[i].convert)(result);
- result = base_classes()[i].class_object->try_base_class_conversions(object);
- if(result)
- return (*base_classes()[i].convert)(result);
+
+ void* result1 = base_classes()[i].class_object->convert_from_holder(object);
+ if (result1)
+ return (*base_classes()[i].convert)(result1);
+
+ void* result2 = base_classes()[i].class_object->try_base_class_conversions(object);
+ if (result2)
+ return (*base_classes()[i].convert)(result2);
}
return 0;
}
-void * ExtensionClassBase::try_derived_class_conversions(InstanceHolderBase * object) const
+void* ExtensionClassBase::try_derived_class_conversions(InstanceHolderBase* object) const
{
- void * result = 0;
- for(int i=0; iconvert_from_holder(object);
- if(result)
- return (*derived_classes()[i].convert)(result);
- result = derived_classes()[i].class_object->try_derived_class_conversions(object);
- if(result)
- return (*derived_classes()[i].convert)(result);
+ void* result1 = derived_classes()[i].class_object->convert_from_holder(object);
+ if (result1)
+ return (*derived_classes()[i].convert)(result1);
+
+ void* result2 = derived_classes()[i].class_object->try_derived_class_conversions(object);
+ if (result2)
+ return (*derived_classes()[i].convert)(result2);
}
return 0;
}
diff --git a/extclass_demo.cpp b/extclass_demo.cpp
index 59e8099f..18050f7d 100644
--- a/extclass_demo.cpp
+++ b/extclass_demo.cpp
@@ -8,6 +8,7 @@
#include "extclass_demo.h"
#include "class_wrapper.h"
#include // used for portability on broken compilers
+#include
namespace extclass_demo {
@@ -476,6 +477,50 @@ int testCallback(CallbackTestBase * b, int i)
return b->testCallback(i);
}
+typedef boost::rational Ratio;
+
+py::String ratio_str(const Ratio& r)
+{
+ char buf[200];
+
+ if (r.denominator() == 1)
+ sprintf(buf, "%d", r.numerator());
+ else
+ sprintf(buf, "%d/%d", r.numerator(), r.denominator());
+
+ return py::String(buf);
+}
+
+py::String ratio_repr(const Ratio& r)
+{
+ char buf[200];
+ sprintf(buf, "Rational(%d, %d)", r.numerator(), r.denominator());
+ return py::String(buf);
+}
+
+py::Tuple ratio_coerce(const Ratio& r1, int r2)
+{
+ return py::Tuple(r1, Ratio(r2));
+}
+
+// The most reliable way, across compilers, to grab the particular abs function
+// we're interested in.
+Ratio ratio_abs(const Ratio& r)
+{
+ return boost::abs(r);
+}
+
+// An experiment, to be integrated into the py_cpp library at some point.
+template
+struct StandardOps
+{
+ static T add(const T& x, const T& y) { return x + y; }
+ static T sub(const T& x, const T& y) { return x - y; }
+ static T mul(const T& x, const T& y) { return x * y; }
+ static T div(const T& x, const T& y) { return x / y; }
+ static T cmp(const T& x, const T& y) { return std::less()(x, y) ? -1 : std::less()(y, x) ? 1 : 0; }
+};
+
/************************************************************/
/* */
/* init the module */
@@ -501,6 +546,21 @@ void init_module(py::Module& m)
m.def(first_string, "first_string");
m.def(second_string, "second_string");
+ // This shows the wrapping of a 3rd-party numeric type.
+ py::ClassWrapper > rational(m, "Rational");
+ rational.def(py::Constructor());
+ rational.def(py::Constructor());
+ rational.def(py::Constructor<>());
+ rational.def(StandardOps::add, "__add__");
+ rational.def(StandardOps::sub, "__sub__");
+ rational.def(StandardOps::mul, "__mul__");
+ rational.def(StandardOps::div, "__div__");
+ rational.def(StandardOps::cmp, "__cmp__");
+ rational.def(ratio_coerce, "__coerce__");
+ rational.def(ratio_str, "__str__");
+ rational.def(ratio_repr, "__repr__");
+ rational.def(ratio_abs, "__abs__");
+
py::ClassWrapper range(m, "Range");
range.def(py::Constructor());
range.def(py::Constructor());
diff --git a/newtypes.cpp b/newtypes.cpp
index e0b4223f..8c75795b 100644
--- a/newtypes.cpp
+++ b/newtypes.cpp
@@ -86,21 +86,13 @@ static MethodStruct* enable_method(const MethodStruct* base, MemberPtr p, Fn f)
return const_cast(detail::UniquePodSet::instance().get(new_value));
}
-// TODO: is there a problem with calling convention here, or can I really pass a
-// pointer to a C++ linkage function as a C-linkage function pointer? The
-// compilers seem to swallow it, but is it legal? Symantec C++ for Mac didn't
-// behave this way, FWIW.
-// Using C++ linkage allows us to keep the virtual function members of
-// TypeObjectBase private and use friendship to get them called.
+namespace {
-extern "C" {
-
-static PyObject* do_instance_repr(PyObject* instance)
+PyObject* call(PyObject* instance, PyObject* (TypeObjectBase::*f)(PyObject*) const)
{
try
{
- return static_cast(instance->ob_type)
- ->instance_repr(instance);
+ return (static_cast(instance->ob_type)->*f)(instance);
}
catch(...)
{
@@ -109,12 +101,14 @@ static PyObject* do_instance_repr(PyObject* instance)
}
}
-static int do_instance_compare(PyObject* instance, PyObject* other)
+// Naming this differently allows us to use it for functions returning long on
+// compilers without partial ordering
+template
+R int_call(PyObject* instance, R (TypeObjectBase::*f)(PyObject*) const)
{
try
{
- return static_cast(instance->ob_type)
- ->instance_compare(instance, other);
+ return (static_cast(instance->ob_type)->*f)(instance);
}
catch(...)
{
@@ -123,12 +117,18 @@ static int do_instance_compare(PyObject* instance, PyObject* other)
}
}
-static PyObject* do_instance_str(PyObject* instance)
+// Implemented in terms of int_call, above
+int call(PyObject* instance, int (TypeObjectBase::*f)(PyObject*) const)
+{
+ return int_call(instance, f);
+}
+
+template
+PyObject* call(PyObject* instance, PyObject* (TypeObjectBase::*f)(PyObject*, A1) const, A1 a1)
{
try
{
- return static_cast(instance->ob_type)
- ->instance_str(instance);
+ return (static_cast(instance->ob_type)->*f)(instance, a1);
}
catch(...)
{
@@ -137,12 +137,40 @@ static PyObject* do_instance_str(PyObject* instance)
}
}
-static long do_instance_hash(PyObject* instance)
+template
+int call(PyObject* instance, int (TypeObjectBase::*f)(PyObject*, A1) const, A1 a1)
{
try
{
- return static_cast(instance->ob_type)
- ->instance_hash(instance);
+ return (static_cast(instance->ob_type)->*f)(instance, a1);
+ }
+ catch(...)
+ {
+ handle_exception();
+ return -1;
+ }
+}
+
+template
+PyObject* call(PyObject* instance, PyObject* (TypeObjectBase::*f)(PyObject*, A1, A2) const, A1 a1, A2 a2)
+{
+ try
+ {
+ return (static_cast(instance->ob_type)->*f)(instance, a1, a2);
+ }
+ catch(...)
+ {
+ handle_exception();
+ return 0;
+ }
+}
+
+template
+int call(PyObject* instance, int (TypeObjectBase::*f)(PyObject*, A1, A2) const, A1 a1, A2 a2)
+{
+ try
+ {
+ return (static_cast(instance->ob_type)->*f)(instance, a1, a2);
}
catch(...)
{
@@ -151,20 +179,70 @@ static long do_instance_hash(PyObject* instance)
}
}
-static PyObject* do_instance_call(PyObject* instance, PyObject* args, PyObject* keywords)
+template
+int call(PyObject* instance, int (TypeObjectBase::*f)(PyObject*, A1, A2, A3) const, A1 a1, A2 a2, A3 a3)
{
try
{
- return static_cast(instance->ob_type)
- ->instance_call(instance, args, keywords);
+ return (static_cast(instance->ob_type)->*f)(instance, a1, a2, a3);
}
catch(...)
{
handle_exception();
- return 0;
+ return -1;
}
}
+int call_length_function(PyObject* instance, int (TypeObjectBase::*f)(PyObject*) const)
+{
+ try
+ {
+ const int outcome =
+ (static_cast(instance->ob_type)->*f)(instance);
+
+ if (outcome < 0)
+ {
+ PyErr_SetString(PyExc_ValueError, "__len__() should return >= 0");
+ return -1;
+ }
+ return outcome;
+ }
+ catch(...)
+ {
+ handle_exception();
+ return -1;
+ }
+}
+
+}
+
+extern "C" {
+
+static PyObject* do_instance_repr(PyObject* instance)
+{
+ return call(instance, &TypeObjectBase::instance_repr);
+}
+
+static int do_instance_compare(PyObject* instance, PyObject* other)
+{
+ return call(instance, &TypeObjectBase::instance_compare, other);
+}
+
+static PyObject* do_instance_str(PyObject* instance)
+{
+ return call(instance, &TypeObjectBase::instance_str);
+}
+
+static long do_instance_hash(PyObject* instance)
+{
+ return int_call(instance, &TypeObjectBase::instance_hash);
+}
+
+static PyObject* do_instance_call(PyObject* instance, PyObject* args, PyObject* keywords)
+{
+ return call(instance, &TypeObjectBase::instance_call, args, keywords);
+}
+
static void do_instance_dealloc(PyObject* instance)
{
try
@@ -181,88 +259,29 @@ static void do_instance_dealloc(PyObject* instance)
static PyObject* do_instance_getattr(PyObject* instance, char* name)
{
- try
- {
- return static_cast(instance->ob_type)
- ->instance_getattr(instance, name);
- }
- catch(...)
- {
- handle_exception();
- return 0;
- }
+ const char* name_ = name;
+ return call(instance, &TypeObjectBase::instance_getattr, name_);
}
static int do_instance_setattr(PyObject* instance, char* name, PyObject* value)
{
- try
- {
- return static_cast(instance->ob_type)
- ->instance_setattr(instance, name, value);
- }
- catch(...)
- {
- handle_exception();
- return -1;
- }
+ const char* name_ = name;
+ return call(instance, &TypeObjectBase::instance_setattr, name_, value);
}
static int do_instance_mp_length(PyObject* instance)
{
- try
- {
- const int outcome =
- static_cast(instance->ob_type)
- ->instance_mapping_length(instance);
-
- if (outcome < 0)
- {
- PyErr_SetString(PyExc_ValueError, "__len__() should return >= 0");
- return -1;
- }
- return outcome;
- }
- catch(...)
- {
- handle_exception();
- return -1;
- }
+ return call_length_function(instance, &TypeObjectBase::instance_mapping_length);
}
static int do_instance_sq_length(PyObject* instance)
{
- try
- {
- const int outcome =
- static_cast(instance->ob_type)
- ->instance_sequence_length(instance);
-
- if (outcome < 0)
- {
- PyErr_SetString(PyExc_ValueError, "__len__() should return >= 0");
- return -1;
- }
- return outcome;
- }
- catch(...)
- {
- handle_exception();
- return -1;
- }
+ return call_length_function(instance, &TypeObjectBase::instance_sequence_length);
}
static PyObject* do_instance_mp_subscript(PyObject* instance, PyObject* index)
{
- try
- {
- return static_cast(instance->ob_type)
- ->instance_mapping_subscript(instance, index);
- }
- catch(...)
- {
- handle_exception();
- return 0;
- }
+ return call(instance, &TypeObjectBase::instance_mapping_subscript, index);
}
static PyObject* do_instance_sq_item(PyObject* instance, int index)
@@ -293,88 +312,149 @@ static PyObject* do_instance_sq_item(PyObject* instance, int index)
static int do_instance_mp_ass_subscript(PyObject* instance, PyObject* index, PyObject* value)
{
- try
- {
- return static_cast(instance->ob_type)
- ->instance_mapping_ass_subscript(instance, index, value);
- }
- catch(...)
- {
- handle_exception();
- return -1;
- }
+ return call(instance, &TypeObjectBase::instance_mapping_ass_subscript, index, value);
}
static int do_instance_sq_ass_item(PyObject* instance, int index, PyObject* value)
{
- try
- {
- return static_cast(instance->ob_type)
- ->instance_sequence_ass_item(instance, index, value);
- }
- catch(...)
- {
- handle_exception();
- return -1;
- }
+ return call(instance, &TypeObjectBase::instance_sequence_ass_item, index, value);
}
static PyObject* do_instance_sq_concat(PyObject* instance, PyObject* other)
{
- try
- {
- return static_cast(instance->ob_type)
- ->instance_sequence_concat(instance, other);
- }
- catch(...)
- {
- handle_exception();
- return 0;
- }
+ return call(instance, &TypeObjectBase::instance_sequence_concat, other);
}
static PyObject* do_instance_sq_repeat(PyObject* instance, int n)
{
- try
- {
- return static_cast(instance->ob_type)
- ->instance_sequence_repeat(instance, n);
- }
- catch(...)
- {
- handle_exception();
- return 0;
- }
+ return call(instance, &TypeObjectBase::instance_sequence_repeat, n);
}
static PyObject* do_instance_sq_slice(
PyObject* instance, int start, int finish)
{
- try
- {
- return static_cast(instance->ob_type)
- ->instance_sequence_slice(instance, start, finish);
- }
- catch(...)
- {
- handle_exception();
- return 0;
- }
+ return call(instance, &TypeObjectBase::instance_sequence_slice, start, finish);
}
static int do_instance_sq_ass_slice(
PyObject* instance, int start, int finish, PyObject* value)
{
- try
- {
- return static_cast(instance->ob_type)
- ->instance_sequence_ass_slice(instance, start, finish, value);
- }
- catch(...)
- {
- handle_exception();
- return -1;
- }
+ return call(instance, &TypeObjectBase::instance_sequence_ass_slice, start, finish, value);
+}
+
+static PyObject* do_instance_nb_add(PyObject* instance, PyObject* other)
+{
+ return call(instance, &TypeObjectBase::instance_number_add, other);
+}
+
+static PyObject* do_instance_nb_subtract(PyObject* instance, PyObject* other)
+{
+ return call(instance, &TypeObjectBase::instance_number_subtract, other);
+}
+
+static PyObject* do_instance_nb_multiply(PyObject* instance, PyObject* other)
+{
+ return call(instance, &TypeObjectBase::instance_number_multiply, other);
+}
+
+static PyObject* do_instance_nb_divide(PyObject* instance, PyObject* other)
+{
+ return call(instance, &TypeObjectBase::instance_number_divide, other);
+}
+
+static PyObject* do_instance_nb_remainder(PyObject* instance, PyObject* other)
+{
+ return call(instance, &TypeObjectBase::instance_number_remainder, other);
+}
+
+static PyObject* do_instance_nb_divmod(PyObject* instance, PyObject* other)
+{
+ return call(instance, &TypeObjectBase::instance_number_divmod, other);
+}
+
+static PyObject* do_instance_nb_power(PyObject* instance, PyObject* exponent, PyObject* modulus)
+{
+ return call(instance, &TypeObjectBase::instance_number_power, exponent, modulus);
+}
+
+static PyObject* do_instance_nb_negative(PyObject* instance)
+{
+ return call(instance, &TypeObjectBase::instance_number_negative);
+}
+
+static PyObject* do_instance_nb_positive(PyObject* instance)
+{
+ return call(instance, &TypeObjectBase::instance_number_positive);
+}
+
+static PyObject* do_instance_nb_absolute(PyObject* instance)
+{
+ return call(instance, &TypeObjectBase::instance_number_absolute);
+}
+
+static int do_instance_nb_nonzero(PyObject* instance)
+{
+ return call(instance, &TypeObjectBase::instance_number_nonzero);
+}
+
+static PyObject* do_instance_nb_invert(PyObject* instance)
+{
+ return call(instance, &TypeObjectBase::instance_number_invert);
+}
+
+
+static PyObject* do_instance_nb_lshift(PyObject* instance, PyObject* other)
+{
+ return call(instance, &TypeObjectBase::instance_number_lshift, other);
+}
+
+static PyObject* do_instance_nb_rshift(PyObject* instance, PyObject* other)
+{
+ return call(instance, &TypeObjectBase::instance_number_rshift, other);
+}
+
+static PyObject* do_instance_nb_and(PyObject* instance, PyObject* other)
+{
+ return call(instance, &TypeObjectBase::instance_number_and, other);
+}
+
+static PyObject* do_instance_nb_xor(PyObject* instance, PyObject* other)
+{
+ return call(instance, &TypeObjectBase::instance_number_xor, other);
+}
+
+static PyObject* do_instance_nb_or(PyObject* instance, PyObject* other)
+{
+ return call(instance, &TypeObjectBase::instance_number_or, other);
+}
+
+static int do_instance_nb_coerce(PyObject**instance, PyObject**other)
+{
+ return call(*instance, &TypeObjectBase::instance_number_coerce, instance, other);
+}
+static PyObject* do_instance_nb_int(PyObject* instance)
+{
+ return call(instance, &TypeObjectBase::instance_number_int);
+}
+
+static PyObject* do_instance_nb_long(PyObject* instance)
+{
+ return call(instance, &TypeObjectBase::instance_number_long);
+}
+
+static PyObject* do_instance_nb_float(PyObject* instance)
+{
+ return call(instance, &TypeObjectBase::instance_number_float);
+}
+
+static PyObject* do_instance_nb_oct(PyObject* instance)
+{
+ return call(instance, &TypeObjectBase::instance_number_oct);
+}
+
+static PyObject* do_instance_nb_hex(PyObject* instance)
+{
+ return call(instance, &TypeObjectBase::instance_number_hex);
}
}
@@ -402,6 +482,7 @@ template struct category_type;
DECLARE_CAPABILITY_TYPE(mapping, PyMappingMethods);
DECLARE_CAPABILITY_TYPE(sequence, PySequenceMethods);
+DECLARE_CAPABILITY_TYPE(number, PyNumberMethods);
const CapabilityEntry capabilities[] = {
CAPABILITY(hash),
@@ -422,7 +503,31 @@ const CapabilityEntry capabilities[] = {
CAPABILITY2(sequence, sq_concat),
CAPABILITY2(sequence, sq_repeat),
CAPABILITY2(sequence, sq_slice),
- CAPABILITY2(sequence, sq_ass_slice)
+ CAPABILITY2(sequence, sq_ass_slice),
+
+ CAPABILITY2(number, nb_add),
+ CAPABILITY2(number, nb_subtract),
+ CAPABILITY2(number, nb_multiply),
+ CAPABILITY2(number, nb_divide),
+ CAPABILITY2(number, nb_remainder),
+ CAPABILITY2(number, nb_divmod),
+ CAPABILITY2(number, nb_power),
+ CAPABILITY2(number, nb_negative),
+ CAPABILITY2(number, nb_positive),
+ CAPABILITY2(number, nb_absolute),
+ CAPABILITY2(number, nb_nonzero),
+ CAPABILITY2(number, nb_invert),
+ CAPABILITY2(number, nb_lshift),
+ CAPABILITY2(number, nb_rshift),
+ CAPABILITY2(number, nb_and),
+ CAPABILITY2(number, nb_xor),
+ CAPABILITY2(number, nb_or),
+ CAPABILITY2(number, nb_coerce),
+ CAPABILITY2(number, nb_int),
+ CAPABILITY2(number, nb_long),
+ CAPABILITY2(number, nb_float),
+ CAPABILITY2(number, nb_oct),
+ CAPABILITY2(number, nb_hex)
};
const std::size_t num_capabilities = PY_ARRAY_LENGTH(capabilities);
@@ -621,6 +726,121 @@ int TypeObjectBase::instance_sequence_ass_slice(PyObject*, int, int, PyObject*)
return unimplemented("instance_sequence_ass_slice");
}
+PyObject* TypeObjectBase::instance_number_add(PyObject*, PyObject*) const
+{
+ return unimplemented("instance_number_add");
+}
+
+PyObject* TypeObjectBase::instance_number_subtract(PyObject*, PyObject*) const
+{
+ return unimplemented("instance_number_subtract");
+}
+
+PyObject* TypeObjectBase::instance_number_multiply(PyObject*, PyObject*) const
+{
+ return unimplemented("instance_number_multiply");
+}
+
+PyObject* TypeObjectBase::instance_number_divide(PyObject*, PyObject*) const
+{
+ return unimplemented("instance_number_divide");
+}
+
+PyObject* TypeObjectBase::instance_number_remainder(PyObject*, PyObject*) const
+{
+ return unimplemented("instance_number_remainder");
+}
+
+PyObject* TypeObjectBase::instance_number_divmod(PyObject*, PyObject*) const
+{
+ return unimplemented("instance_number_divmod");
+}
+
+PyObject* TypeObjectBase::instance_number_power(PyObject*, PyObject*, PyObject*) const
+{
+ return unimplemented("instance_number_divmod");
+}
+
+PyObject* TypeObjectBase::instance_number_negative(PyObject*) const
+{
+ return unimplemented("instance_number_negative");
+}
+
+PyObject* TypeObjectBase::instance_number_positive(PyObject*) const
+{
+ return unimplemented("instance_number_positive");
+}
+
+PyObject* TypeObjectBase::instance_number_absolute(PyObject*) const
+{
+ return unimplemented("instance_number_absolute");
+}
+
+int TypeObjectBase::instance_number_nonzero(PyObject*) const
+{
+ return unimplemented("instance_number_nonzero");
+}
+
+PyObject* TypeObjectBase::instance_number_invert(PyObject*) const
+{
+ return unimplemented("instance_number_invert");
+}
+
+PyObject* TypeObjectBase::instance_number_lshift(PyObject*, PyObject*) const
+{
+ return unimplemented("instance_number_lshift");
+}
+
+PyObject* TypeObjectBase::instance_number_rshift(PyObject*, PyObject*) const
+{
+ return unimplemented("instance_number_rshift");
+}
+
+PyObject* TypeObjectBase::instance_number_and(PyObject*, PyObject*) const
+{
+ return unimplemented("instance_number_and");
+}
+
+PyObject* TypeObjectBase::instance_number_xor(PyObject*, PyObject*) const
+{
+ return unimplemented("instance_number_xor");
+}
+
+PyObject* TypeObjectBase::instance_number_or(PyObject*, PyObject*) const
+{
+ return unimplemented("instance_number_or");
+}
+
+int TypeObjectBase::instance_number_coerce(PyObject*, PyObject**, PyObject**) const
+{
+ return unimplemented("instance_number_coerce");
+}
+
+PyObject* TypeObjectBase::instance_number_int(PyObject*) const
+{
+ return unimplemented("instance_number_int");
+}
+
+PyObject* TypeObjectBase::instance_number_long(PyObject*) const
+{
+ return unimplemented("instance_number_long");
+}
+
+PyObject* TypeObjectBase::instance_number_float(PyObject*) const
+{
+ return unimplemented("instance_number_float");
+}
+
+PyObject* TypeObjectBase::instance_number_oct(PyObject*) const
+{
+ return unimplemented("instance_number_oct");
+}
+
+PyObject* TypeObjectBase::instance_number_hex(PyObject*) const
+{
+ return unimplemented("instance_number_hex");
+}
+
TypeObjectBase::~TypeObjectBase()
{
}
diff --git a/newtypes.h b/newtypes.h
index 5458bcf6..ec8839a8 100644
--- a/newtypes.h
+++ b/newtypes.h
@@ -44,7 +44,14 @@ class TypeObjectBase : public PythonType
hash, call, str, getattr, setattr, compare, repr,
mapping_length, mapping_subscript, mapping_ass_subscript,
sequence_length, sequence_item, sequence_ass_item,
- sequence_concat, sequence_repeat, sequence_slice, sequence_ass_slice
+ sequence_concat, sequence_repeat, sequence_slice, sequence_ass_slice,
+
+ number_add, number_subtract, number_multiply, number_divide,
+ number_remainder, number_divmod, number_power, number_negative,
+ number_positive, number_absolute, number_nonzero, number_invert,
+ number_lshift, number_rshift, number_and, number_xor, number_or,
+ number_coerce, number_int, number_long, number_float, number_oct,
+ number_hex
};
void enable(Capability);
@@ -77,7 +84,31 @@ class TypeObjectBase : public PythonType
virtual PyObject* instance_sequence_slice(PyObject* instance, int start, int finish) const;
virtual int instance_sequence_ass_item(PyObject* instance, int n, PyObject* value) const;
virtual int instance_sequence_ass_slice(PyObject* instance, int start, int finish, PyObject* value) const;
-
+
+ public: // Callbacks for number methods
+ virtual PyObject* instance_number_add(PyObject*, PyObject*) const;
+ virtual PyObject* instance_number_subtract(PyObject*, PyObject*) const;
+ virtual PyObject* instance_number_multiply(PyObject*, PyObject*) const;
+ virtual PyObject* instance_number_divide(PyObject*, PyObject*) const;
+ virtual PyObject* instance_number_remainder(PyObject*, PyObject*) const;
+ virtual PyObject* instance_number_divmod(PyObject*, PyObject*) const;
+ virtual PyObject* instance_number_power(PyObject*, PyObject*, PyObject*) const;
+ virtual PyObject* instance_number_negative(PyObject*) const;
+ virtual PyObject* instance_number_positive(PyObject*) const;
+ virtual PyObject* instance_number_absolute(PyObject*) const;
+ virtual int instance_number_nonzero(PyObject*) const;
+ virtual PyObject* instance_number_invert(PyObject*) const;
+ virtual PyObject* instance_number_lshift(PyObject*, PyObject*) const;
+ virtual PyObject* instance_number_rshift(PyObject*, PyObject*) const;
+ virtual PyObject* instance_number_and(PyObject*, PyObject*) const;
+ virtual PyObject* instance_number_xor(PyObject*, PyObject*) const;
+ virtual PyObject* instance_number_or(PyObject*, PyObject*) const;
+ virtual int instance_number_coerce(PyObject*, PyObject**, PyObject**) const;
+ virtual PyObject* instance_number_int(PyObject*) const;
+ virtual PyObject* instance_number_long(PyObject*) const;
+ virtual PyObject* instance_number_float(PyObject*) const;
+ virtual PyObject* instance_number_oct(PyObject*) const;
+ virtual PyObject* instance_number_hex(PyObject*) const;
};
template
diff --git a/objects.h b/objects.h
index c2d1eabe..4f54befc 100644
--- a/objects.h
+++ b/objects.h
@@ -13,6 +13,7 @@
# include "pyconfig.h"
# include "pyptr.h"
# include "boost/operators.hpp"
+# include
namespace py {
@@ -36,8 +37,31 @@ class Tuple : public Object
public:
Tuple(std::size_t n = 0);
explicit Tuple(Ptr p);
+
+ template
+ Tuple(const std::pair& x)
+ : Object(Ptr(PyTuple_New(2)))
+ {
+ set_item(0, Ptr(to_python(x.first)));
+ set_item(1, Ptr(to_python(x.second)));
+ }
- Tuple(const Ptr* start, const Ptr* finish); // not yet implemented.
+ template
+ Tuple(const First& first, const Second& second)
+ : Object(Ptr(PyTuple_New(2)))
+ {
+ set_item(0, Ptr(to_python(first)));
+ set_item(1, Ptr(to_python(second)));
+ }
+
+ template
+ Tuple(const First& first, const Second& second, const Third& third)
+ : Object(Ptr(PyTuple_New(3)))
+ {
+ set_item(0, Ptr(to_python(first)));
+ set_item(1, Ptr(to_python(second)));
+ set_item(2, Ptr(to_python(third)));
+ }
static PyTypeObject* type_object();
static bool accepts(Ptr p);
diff --git a/py.h b/py.h
index 2cf89807..06365764 100644
--- a/py.h
+++ b/py.h
@@ -165,6 +165,11 @@ PyObject* to_python(boost::shared_ptr p)
// inline implementations
//
+inline PyObject* to_python(double d)
+{
+ return PyFloat_FromDouble(d);
+}
+
inline PyObject* to_python(long l)
{
return PyInt_FromLong(l);
diff --git a/subclass.cpp b/subclass.cpp
index 3f1d25ec..3a133be0 100644
--- a/subclass.cpp
+++ b/subclass.cpp
@@ -38,12 +38,8 @@ PyObject* Instance::getattr(const char* name, bool use_special_function)
}
else
{
- // Suspend the error while we try special methods method (if any).
-#if 0
- SuspendError suspended_error(SuspendError::discard_new_error);
-#else
+ // Clear the error while we try special methods method (if any).
PyErr_Clear();
-#endif
// First we try the special method that comes from concatenating
// "__getattr__" and and 2 trailing underscores. This is an
@@ -67,15 +63,11 @@ PyObject* Instance::getattr(const char* name, bool use_special_function)
}
// If there is no such method, throw now.
-#if 0
- suspended_error.throw_if_error();
-#else
if (PyErr_Occurred())
{
PyErr_SetString(PyExc_AttributeError, name);
throw ErrorAlreadySet();
}
-#endif
// Take ownership of the method
Ptr owner(getattr_method);
@@ -224,6 +216,131 @@ void Instance::set_slice(int start, int finish, PyObject* value)
Callback::call_method(this, "__setslice__", start, finish, value);
}
+PyObject* Instance::add(PyObject* other)
+{
+ return Callback::call_method(this, "__add__", other);
+}
+
+PyObject* Instance::subtract(PyObject* other)
+{
+ return Callback::call_method(this, "__sub__", other);
+}
+
+PyObject* Instance::multiply(PyObject* other)
+{
+ return Callback::call_method(this, "__mul__", other);
+}
+
+PyObject* Instance::divide(PyObject* other)
+{
+ return Callback::call_method(this, "__div__", other);
+}
+
+PyObject* Instance::remainder(PyObject* other)
+{
+ return Callback::call_method(this, "__mod__", other);
+}
+
+PyObject* Instance::divmod(PyObject* other)
+{
+ return Callback::call_method(this, "__divmod__", other);
+}
+
+PyObject* Instance::power(PyObject* exponent, PyObject* modulus)
+{
+ if (as_object(modulus->ob_type) == Py_None)
+ return Callback::call_method(this, "__pow__", exponent);
+ else
+ return Callback::call_method(this, "__pow__", exponent, modulus);
+}
+
+PyObject* Instance::negative()
+{
+ return Callback::call_method(this, "__neg__");
+}
+
+PyObject* Instance::positive()
+{
+ return Callback::call_method(this, "__pos__");
+}
+
+PyObject* Instance::absolute()
+{
+ return Callback::call_method(this, "__abs__");
+}
+
+int Instance::nonzero()
+{
+ return Callback::call_method(this, "__nonzero__");
+}
+
+PyObject* Instance::invert()
+{
+ return Callback::call_method(this, "__invert__");
+}
+
+PyObject* Instance::lshift(PyObject* other)
+{
+ return Callback::call_method(this, "__lshift__", other);
+}
+
+PyObject* Instance::rshift(PyObject* other)
+{
+ return Callback::call_method(this, "__rshift__", other);
+}
+
+PyObject* Instance::do_and(PyObject* other)
+{
+ return Callback::call_method(this, "__and__", other);
+}
+
+PyObject* Instance::do_xor(PyObject* other)
+{
+ return Callback::call_method(this, "__xor__", other);
+}
+
+PyObject* Instance::do_or(PyObject* other)
+{
+ return Callback::call_method(this, "__or__", other);
+}
+
+int Instance::coerce(PyObject** x, PyObject** y)
+{
+ assert(this == *x);
+
+ // Coerce must return a tuple
+ Tuple result(Callback::call_method(this, "__coerce__", *y));
+
+ *x = result[0].release();
+ *y = result[1].release();
+ return 0;
+}
+
+PyObject* Instance::as_int()
+{
+ return Callback::call_method(this, "__int__");
+}
+
+PyObject* Instance::as_long()
+{
+ return Callback::call_method(this, "__long__");
+}
+
+PyObject* Instance::as_float()
+{
+ return Callback::call_method(this, "__float__");
+}
+
+PyObject* Instance::oct()
+{
+ return Callback::call_method(this, "__oct__");
+}
+
+PyObject* Instance::hex()
+{
+ return Callback::call_method(this, "__hex__");
+}
+
namespace {
struct NamedCapability
{
@@ -250,7 +367,30 @@ namespace {
{ "__delitem__", TypeObjectBase::sequence_ass_item },
{ "__getslice__", TypeObjectBase::sequence_slice },
{ "__setslice__", TypeObjectBase::sequence_ass_slice },
- { "__delslice__", TypeObjectBase::sequence_ass_slice }
+ { "__delslice__", TypeObjectBase::sequence_ass_slice },
+ { "__add__", TypeObjectBase::number_add },
+ { "__sub__", TypeObjectBase::number_subtract },
+ { "__mul__", TypeObjectBase::number_multiply },
+ { "__div__", TypeObjectBase::number_divide },
+ { "__mod__", TypeObjectBase::number_remainder },
+ { "__divmod__", TypeObjectBase::number_divmod },
+ { "__pow__", TypeObjectBase::number_power },
+ { "__neg__", TypeObjectBase::number_negative },
+ { "__pos__", TypeObjectBase::number_positive },
+ { "__abs__", TypeObjectBase::number_absolute },
+ { "__nonzero__", TypeObjectBase::number_nonzero },
+ { "__invert__", TypeObjectBase::number_invert },
+ { "__lshift__", TypeObjectBase::number_lshift },
+ { "__rshift__", TypeObjectBase::number_rshift },
+ { "__and__", TypeObjectBase::number_and },
+ { "__xor__", TypeObjectBase::number_xor },
+ { "__or__", TypeObjectBase::number_or },
+ { "__coerce__", TypeObjectBase::number_coerce },
+ { "__int__", TypeObjectBase::number_int },
+ { "__long__", TypeObjectBase::number_long },
+ { "__float__", TypeObjectBase::number_float },
+ { "__oct__", TypeObjectBase::number_oct },
+ { "__hex__", TypeObjectBase::number_hex }
};
bool is_prefix(const char* s1, const char* s2)
diff --git a/subclass.h b/subclass.h
index 0f2366b5..778f8519 100644
--- a/subclass.h
+++ b/subclass.h
@@ -44,7 +44,32 @@ class Instance : public PythonObject
// Sequence methods
PyObject* get_slice(int start, int finish);
void set_slice(int start, int finish, PyObject* value);
-
+
+ // Number methods
+ PyObject* add(PyObject* other);
+ PyObject* subtract(PyObject* other);
+ PyObject* multiply(PyObject* other);
+ PyObject* divide(PyObject* other);
+ PyObject* remainder(PyObject* other);
+ PyObject* divmod(PyObject* other);
+ PyObject* power(PyObject*, PyObject*);
+ PyObject* negative();
+ PyObject* positive();
+ PyObject* absolute();
+ int nonzero();
+ PyObject* invert();
+ PyObject* lshift(PyObject* other);
+ PyObject* rshift(PyObject* other);
+ PyObject* do_and(PyObject* other);
+ PyObject* do_xor(PyObject* other);
+ PyObject* do_or(PyObject* other);
+ int coerce(PyObject**, PyObject**);
+ PyObject* as_int();
+ PyObject* as_long();
+ PyObject* as_float();
+ PyObject* oct();
+ PyObject* hex();
+
private: // noncopyable, without the size bloat
Instance(const Instance&);
void operator=(const Instance&);
@@ -98,6 +123,31 @@ class Class
PyObject* instance_sequence_slice(PyObject*, int start, int finish) const;
int instance_sequence_ass_slice(PyObject*, int start, int finish, PyObject* value) const;
+ private: // Implement number methods on instances
+ PyObject* instance_number_add(PyObject*, PyObject*) const;
+ PyObject* instance_number_subtract(PyObject*, PyObject*) const;
+ PyObject* instance_number_multiply(PyObject*, PyObject*) const;
+ PyObject* instance_number_divide(PyObject*, PyObject*) const;
+ PyObject* instance_number_remainder(PyObject*, PyObject*) const;
+ PyObject* instance_number_divmod(PyObject*, PyObject*) const;
+ PyObject* instance_number_power(PyObject*, PyObject*, PyObject*) const;
+ PyObject* instance_number_negative(PyObject*) const;
+ PyObject* instance_number_positive(PyObject*) const;
+ PyObject* instance_number_absolute(PyObject*) const;
+ int instance_number_nonzero(PyObject*) const;
+ PyObject* instance_number_invert(PyObject*) const;
+ PyObject* instance_number_lshift(PyObject*, PyObject*) const;
+ PyObject* instance_number_rshift(PyObject*, PyObject*) const;
+ PyObject* instance_number_and(PyObject*, PyObject*) const;
+ PyObject* instance_number_xor(PyObject*, PyObject*) const;
+ PyObject* instance_number_or(PyObject*, PyObject*) const;
+ int instance_number_coerce(PyObject*, PyObject**, PyObject**) const;
+ PyObject* instance_number_int(PyObject*) const;
+ PyObject* instance_number_long(PyObject*) const;
+ PyObject* instance_number_float(PyObject*) const;
+ PyObject* instance_number_oct(PyObject*) const;
+ PyObject* instance_number_hex(PyObject*) const;
+
private: // Miscellaneous "special" methods
PyObject* instance_call(PyObject* instance, PyObject* args, PyObject* keywords) const;
@@ -322,6 +372,144 @@ PyObject* Class::instance_call(PyObject* instance, PyObject* args, PyObject*
return Downcast(instance)->call(args, keywords);
}
+template
+PyObject* Class::instance_number_add(PyObject* instance, PyObject* other) const
+{
+ return Downcast(instance)->add(other);
+}
+
+template
+PyObject* Class::instance_number_subtract(PyObject* instance, PyObject* other) const
+{
+ return Downcast(instance)->subtract(other);
+}
+
+template
+PyObject* Class::instance_number_multiply(PyObject* instance, PyObject* other) const
+{
+ return Downcast(instance)->multiply(other);
+}
+
+template
+PyObject* Class::instance_number_divide(PyObject* instance, PyObject* other) const
+{
+ return Downcast(instance)->divide(other);
+}
+
+template
+PyObject* Class::instance_number_remainder(PyObject* instance, PyObject* other) const
+{
+ return Downcast(instance)->remainder(other);
+}
+
+template
+PyObject* Class::instance_number_divmod(PyObject* instance, PyObject* other) const
+{
+ return Downcast(instance)->divmod(other);
+}
+
+template
+PyObject* Class::instance_number_power(PyObject* instance, PyObject* exponent, PyObject* modulus) const
+{
+ return Downcast(instance)->power(exponent, modulus);
+}
+
+template
+PyObject* Class::instance_number_negative(PyObject* instance) const
+{
+ return Downcast(instance)->negative();
+}
+
+template
+PyObject* Class::instance_number_positive(PyObject* instance) const
+{
+ return Downcast(instance)->positive();
+}
+
+template
+PyObject* Class::instance_number_absolute(PyObject* instance) const
+{
+ return Downcast(instance)->absolute();
+}
+
+template
+int Class::instance_number_nonzero(PyObject* instance) const
+{
+ return Downcast(instance)->nonzero();
+}
+
+template
+PyObject* Class::instance_number_invert(PyObject* instance) const
+{
+ return Downcast(instance)->invert();
+}
+
+template
+PyObject* Class::instance_number_lshift(PyObject* instance, PyObject* other) const
+{
+ return Downcast(instance)->lshift(other);
+}
+
+template
+PyObject* Class::instance_number_rshift(PyObject* instance, PyObject* other) const
+{
+ return Downcast(instance)->rshift(other);
+}
+
+template
+PyObject* Class::instance_number_and(PyObject* instance, PyObject* other) const
+{
+ return Downcast(instance)->do_and(other);
+}
+
+template
+PyObject* Class::instance_number_xor(PyObject* instance, PyObject* other) const
+{
+ return Downcast(instance)->do_xor(other);
+}
+
+template
+PyObject* Class::instance_number_or(PyObject* instance, PyObject* other) const
+{
+ return Downcast(instance)->do_or(other);
+}
+
+template
+int Class::instance_number_coerce(PyObject* instance, PyObject** x, PyObject** y) const
+{
+ return Downcast(instance)->coerce(x, y);
+}
+
+template
+PyObject* Class::instance_number_int(PyObject* instance) const
+{
+ return Downcast(instance)->as_int();
+}
+
+template
+PyObject* Class::instance_number_long(PyObject* instance) const
+{
+ return Downcast(instance)->as_long();
+}
+
+template
+PyObject* Class::instance_number_float(PyObject* instance) const
+{
+ return Downcast(instance)->as_float();
+}
+
+template
+PyObject* Class::instance_number_oct(PyObject* instance) const
+{
+ return Downcast(instance)->oct();
+}
+
+template
+PyObject* Class::instance_number_hex(PyObject* instance) const
+{
+ return Downcast(instance)->hex();
+}
+
template
Dict& Class::dict()
{
diff --git a/test_extclass.py b/test_extclass.py
index 1ef74a7c..648b3e81 100644
--- a/test_extclass.py
+++ b/test_extclass.py
@@ -264,6 +264,22 @@ Sequence tests:
>>> map(lambda x:x, Range(3, 10)[0:4])
[3, 4, 5, 6]
+Numeric tests:
+ >>> x = Rational(2,3)
+ >>> y = Rational(1,4)
+ >>> print x + y
+ 11/12
+ >>> print x - y
+ 5/12
+ >>> print x * y
+ 1/6
+ >>> print x / y
+ 8/3
+ >>> print x + 1 # testing coercion
+ 5/3
+ >>> print 1 + x # coercion the other way
+ 5/3
+
delete non-existent attribute:
del m.foobar
Traceback (innermost last):
diff --git a/todo.txt b/todo.txt
index 80514798..51967244 100644
--- a/todo.txt
+++ b/todo.txt
@@ -7,14 +7,15 @@ Report Cygwin linker memory issues
handle more arguments
MI from both ExtensionClasses and Python classes, or at least don't crash(!)
Remove one level of indirection on type objects (no vtbl?).
-Much more testing, especially of things in objects.h
Make multiple inheritance from real Python classes work - I don't think this is possible
Handle polymorphism (passing a Wrapped as a Base*).
Specializations of Caller<> for commmon combinations of argument types (?)
special member functions for numeric types
pickling support
testing with Python 2.0
-Make abstract classes non-instantiable
+Make abstract classes non-instantiable (?)
+Much more testing, especially of things in objects.h
+Support for Python LONG types in Objects.h
Documentation:
building
@@ -31,6 +32,7 @@ Documentation:
differences between Python classes and ExtensionClasses
additional capabilities of ExtensionClasses
+ slice adjustment
exception handling