2
0
mirror of https://github.com/boostorg/python.git synced 2026-01-27 07:02:15 +00:00

This commit was manufactured by cvs2svn to create branch

'to_python_experiments'.

[SVN r8004]
This commit is contained in:
nobody
2000-10-18 16:09:58 +00:00
parent af426418f3
commit 8e74a5902a
18 changed files with 1554 additions and 191 deletions

View File

@@ -65,6 +65,45 @@ class ClassWrapper
template <class MemberType>
void def_read_write(MemberType T::*pm, const char* name)
{ m_class->def_read_write(pm, name); }
// declare the given class a base class of this one and register
// conversion functions
template <class S, class V>
void declare_base(ClassWrapper<S, V> const & base)
{
m_class->declare_base(base.get_extension_class());
}
// declare the given class a base class of this one and register
// upcast conversion function
template <class S, class V>
void declare_base(ClassWrapper<S, V> const & base, WithoutDowncast)
{
m_class->declare_base(base.get_extension_class(), without_downcast);
}
// declare the given class a base class of this one and register
// conversion functions
template <class S, class V>
void declare_base(ExtensionClass<S, V> * base)
{
m_class->declare_base(base);
}
// declare the given class a base class of this one and register
// upcast conversion function
template <class S, class V>
void declare_base(ExtensionClass<S, V> * base, WithoutDowncast)
{
m_class->declare_base(base, without_downcast);
}
// get the embedded ExtensioClass object
ExtensionClass<T, U> * get_extension_class() const
{
return m_class.get();
}
private:
PyPtr<ExtensionClass<T, U> > m_class;
};

View File

@@ -149,9 +149,8 @@
Acquisition</a>.
<li>
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.
</ul>
<p>
Also, the Zope docs say: "The first superclass listed in the class

View File

@@ -157,7 +157,7 @@ void report_missing_instance_data(
}
else
{
two_string_error(PyExc_TypeError, "extension class '%.*s' is not derived from '%.*s'.",
two_string_error(PyExc_TypeError, "extension class '%.*s' is not convertible into '%.*s'.",
instance->ob_type->tp_name, target_class->tp_name);
}
}
@@ -218,6 +218,66 @@ ExtensionClassBase::ExtensionClassBase(const char* name)
{
}
// This function is used in from_python() to convert wrapped classes that are
// related by inheritance. The problem is this: although C++ provides all necessary
// conversion operators, source and target of a conversion must be known at compile
// time. However, in Python we want to convert classes at runtime. The solution is to
// generate conversion functions at compile time, register them within the appropriate
// class objects and call them when a particular runtime conversion is required.
// If functions for any possible conversion have to be stored, their number will grow
// qudratically. To reduce this number, we actually store only conversion functions
// between adjacent levels in the inheritance tree. By traversing the tree recursively,
// we can build any allowed conversion as a concatenation of simple conversions. This
// traversal is done in the functions try_base_class_conversions() and
// try_derived_class_conversions(). If a particular conversion is impossible, all
// conversion functions will return a NULL pointer.
// The function extract_object_from_holder() attempts to actually extract the pointer
// to the contained object from an InstanceHolderBase (a wrapper class). A conversion
// of the held object to 'T *' is allowed when the conversion
// 'dynamic_cast<InstanceHolder<T> *>(an_instance_holder_base)' succeeds.
void* ExtensionClassBase::try_class_conversions(InstanceHolderBase* object) const
{
void* result = try_derived_class_conversions(object);
if(result)
return result;
return try_base_class_conversions(object);
}
void* ExtensionClassBase::try_base_class_conversions(InstanceHolderBase* object) const
{
for (std::size_t i = 0; i < base_classes().size(); ++i)
{
if(base_classes()[i].convert == 0)
continue;
void* result1 = base_classes()[i].class_object->extract_object_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
{
for (std::size_t i = 0; i < derived_classes().size(); ++i)
{
void* result1 = derived_classes()[i].class_object->extract_object_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;
}
void ExtensionClassBase::add_method(Function* method, const char* name)
{
add_method(PyPtr<Function>(method), name);

View File

@@ -27,6 +27,7 @@ namespace py {
// forward declarations
class ExtensionInstance;
class ExtensionClassBase;
template <class T> class InstanceHolder;
template <class T, class U> class InstanceValueHolder;
template <class Ptr, class T> class InstancePtrHolder;
@@ -53,10 +54,39 @@ T* check_non_null(T* p)
template <class T> class HeldInstance;
namespace detail {
typedef void* (*ConversionFunction)(void*);
struct BaseClassInfo
{
BaseClassInfo(ExtensionClassBase* t, ConversionFunction f)
:class_object(t), convert(f)
{}
ExtensionClassBase* class_object;
ConversionFunction convert;
};
typedef BaseClassInfo DerivedClassInfo;
}
class ExtensionClassBase : public Class<ExtensionInstance>
{
public:
ExtensionClassBase(const char* name);
public:
// the purpose of try_class_conversions() and its related functions
// is explained in extclass.cpp
void* try_class_conversions(InstanceHolderBase*) const;
void* try_base_class_conversions(InstanceHolderBase*) const;
void* try_derived_class_conversions(InstanceHolderBase*) const;
private:
virtual void* extract_object_from_holder(InstanceHolderBase* v) const = 0;
virtual std::vector<py::detail::BaseClassInfo> const& base_classes() const = 0;
virtual std::vector<py::detail::DerivedClassInfo> const& derived_classes() const = 0;
protected:
void add_method(PyPtr<Function> method, const char* name);
void add_default_method(PyPtr<Function> method, const char* name);
@@ -72,12 +102,24 @@ template <class T>
class ClassRegistry
{
public:
static Class<ExtensionInstance>* class_object()
static ExtensionClassBase* class_object()
{ return static_class_object; }
static void register_class(py::Class<py::ExtensionInstance>*);
static void unregister_class(py::Class<py::ExtensionInstance>*);
// Register/unregister the Python class object corresponding to T
static void register_class(ExtensionClassBase*);
static void unregister_class(ExtensionClassBase*);
// Establish C++ inheritance relationships
static void register_base_class(py::detail::BaseClassInfo const&);
static void register_derived_class(py::detail::DerivedClassInfo const&);
// Query the C++ inheritance relationships
static std::vector<py::detail::BaseClassInfo> const& base_classes();
static std::vector<py::detail::DerivedClassInfo> const& derived_classes();
private:
static py::Class<py::ExtensionInstance>* static_class_object;
static ExtensionClassBase* static_class_object;
static std::vector<py::detail::BaseClassInfo> static_base_class_info;
static std::vector<py::detail::DerivedClassInfo> static_derived_class_info;
};
#ifdef PY_NO_INLINE_FRIENDS_IN_NAMESPACE // back to global namespace for this GCC bug
@@ -123,6 +165,11 @@ class PyExtensionClassConverters
py::InstanceHolder<T>* held = dynamic_cast<py::InstanceHolder<T>*>(*p);
if (held != 0)
return held->target();
// see extclass.cpp for an explanation of try_class_conversions()
void * target = py::ClassRegistry<T>::class_object()->try_class_conversions(*p);
if(target)
return static_cast<T *>(target);
}
py::report_missing_instance_data(self, py::ClassRegistry<T>::class_object(), typeid(T));
throw py::ArgumentError();
@@ -171,7 +218,6 @@ class PyExtensionClassConverters
return py::PyPtr<py::ExtensionInstance>(new py::ExtensionInstance(class_));
}
// Convert to const T*
friend const T* from_python(PyObject* p, py::Type<const T*>)
{ return from_python(p, py::Type<T*>()); }
@@ -250,6 +296,28 @@ class ReadOnlySetattrFunction : public Function
String m_name;
};
namespace detail
{
template <class From, class To>
struct DefineConversion
{
static void * upcast_ptr(void * v)
{
return static_cast<To *>(static_cast<From *>(v));
}
static void * downcast_ptr(void * v)
{
return dynamic_cast<To *>(static_cast<From *>(v));
}
};
}
enum WithoutDowncast { without_downcast };
// An easy way to make an extension base class which wraps T. Note that Python
// subclasses of this class will simply be Class<ExtensionInstance> objects.
//
@@ -344,10 +412,49 @@ class ExtensionClass
this->def_getter(pm, name);
this->def_setter(pm, name);
}
// declare the given class a base class of this one and register
// up and down conversion functions
template <class S, class V>
void declare_base(ExtensionClass<S, V> * base)
{
// see extclass.cpp for an explanation of why we need to register
// conversion functions
detail::BaseClassInfo baseInfo(base,
&detail::DefineConversion<S, T>::downcast_ptr);
ClassRegistry<T>::register_base_class(baseInfo);
add_base(Ptr(as_object(base), Ptr::new_ref));
detail::DerivedClassInfo derivedInfo(this,
&detail::DefineConversion<T, S>::upcast_ptr);
ClassRegistry<S>::register_derived_class(derivedInfo);
}
// declare the given class a base class of this one and register
// only up conversion function
template <class S, class V>
void declare_base(ExtensionClass<S, V> * base, WithoutDowncast)
{
// see extclass.cpp for an explanation of why we need to register
// conversion functions
detail::BaseClassInfo baseInfo(base, 0);
ClassRegistry<T>::register_base_class(baseInfo);
add_base(Ptr(as_object(base), Ptr::new_ref));
detail::DerivedClassInfo derivedInfo(this,
&detail::DefineConversion<T, S>::upcast_ptr);
ClassRegistry<S>::register_derived_class(derivedInfo);
}
private:
private: // types
typedef InstanceValueHolder<T,U> Holder;
private: // ExtensionClassBase virtual function implementations
std::vector<detail::BaseClassInfo> const& base_classes() const;
std::vector<detail::DerivedClassInfo> const& derived_classes() const;
void* extract_object_from_holder(InstanceHolderBase* v) const;
private: // Utility functions
template <class Signature>
void add_constructor(Signature sig)
{
@@ -425,7 +532,7 @@ class InstancePtrHolder : public InstanceHolder<HeldType>
public:
HeldType* target() { return &*m_ptr; }
PtrType& ptr() { return m_ptr; }
InstancePtrHolder(PtrType ptr) : m_ptr(ptr) {}
private:
PtrType m_ptr;
@@ -464,6 +571,30 @@ ExtensionClass<T, U>::ExtensionClass(const char* name)
ClassRegistry<T>::register_class(this);
}
template <class T, class U>
inline
std::vector<detail::BaseClassInfo> const &
ExtensionClass<T, U>::base_classes() const
{
return ClassRegistry<T>::base_classes();
}
template <class T, class U>
inline
std::vector<detail::DerivedClassInfo> const &
ExtensionClass<T, U>::derived_classes() const
{
return ClassRegistry<T>::derived_classes();
}
template <class T, class U>
void* ExtensionClass<T, U>::extract_object_from_holder(InstanceHolderBase* v) const
{
py::InstanceHolder<T>* held = dynamic_cast<py::InstanceHolder<T>*>(v);
if(held) return held->target();
return 0;
}
template <class T, class U>
ExtensionClass<T, U>::~ExtensionClass()
{
@@ -471,7 +602,7 @@ ExtensionClass<T, U>::~ExtensionClass()
}
template <class T>
inline void ClassRegistry<T>::register_class(Class<ExtensionInstance>* p)
inline void ClassRegistry<T>::register_class(ExtensionClassBase* p)
{
// You're not expected to create more than one of these!
assert(static_class_object == 0);
@@ -479,7 +610,7 @@ inline void ClassRegistry<T>::register_class(Class<ExtensionInstance>* p)
}
template <class T>
inline void ClassRegistry<T>::unregister_class(Class<ExtensionInstance>* p)
inline void ClassRegistry<T>::unregister_class(ExtensionClassBase* p)
{
// The user should be destroying the same object they created.
assert(static_class_object == p);
@@ -487,11 +618,39 @@ inline void ClassRegistry<T>::unregister_class(Class<ExtensionInstance>* p)
static_class_object = 0;
}
template <class T>
void ClassRegistry<T>::register_base_class(py::detail::BaseClassInfo const & i)
{
static_base_class_info.push_back(i);
}
template <class T>
void ClassRegistry<T>::register_derived_class(py::detail::DerivedClassInfo const & i)
{
static_derived_class_info.push_back(i);
}
template <class T>
std::vector<py::detail::BaseClassInfo> const& ClassRegistry<T>::base_classes()
{
return static_base_class_info;
}
template <class T>
std::vector<py::detail::DerivedClassInfo> const& ClassRegistry<T>::derived_classes()
{
return static_derived_class_info;
}
//
// Static data member declaration.
//
template <class T>
Class<py::ExtensionInstance>* ClassRegistry<T>::static_class_object;
ExtensionClassBase* ClassRegistry<T>::static_class_object;
template <class T>
std::vector<py::detail::BaseClassInfo> ClassRegistry<T>::static_base_class_info;
template <class T>
std::vector<py::detail::DerivedClassInfo> ClassRegistry<T>::static_derived_class_info;
} // namespace py

View File

@@ -8,6 +8,7 @@
#include "extclass_demo.h"
#include "class_wrapper.h"
#include <stdio.h> // used for portability on broken compilers
#include <boost/rational.hpp>
namespace extclass_demo {
@@ -290,6 +291,245 @@ long range_hash(const Range& r)
return r.m_start * 123 + r.m_finish;
}
/************************************************************/
/* */
/* some functions to test overloading */
/* */
/************************************************************/
static std::string testVoid()
{
return std::string("Hello world!");
}
static int testInt(int i)
{
return i;
}
static std::string testString(std::string i)
{
return i;
}
static int test2(int i1, int i2)
{
return i1+i2;
}
static int test3(int i1, int i2, int i3)
{
return i1+i2+i3;
}
static int test4(int i1, int i2, int i3, int i4)
{
return i1+i2+i3+i4;
}
static int test5(int i1, int i2, int i3, int i4, int i5)
{
return i1+i2+i3+i4+i5;
}
/************************************************************/
/* */
/* a class to test overloading */
/* */
/************************************************************/
struct OverloadTest
{
OverloadTest(): x_(1000) {}
OverloadTest(int x): x_(x) {}
OverloadTest(int x,int y): x_(x+y) { }
OverloadTest(int x,int y,int z): x_(x+y+z) {}
OverloadTest(int x,int y,int z, int a): x_(x+y+z+a) {}
OverloadTest(int x,int y,int z, int a, int b): x_(x+y+z+a+b) {}
int x() const { return x_; }
void setX(int x) { x_ = x; }
int p1(int x) { return x; }
int p2(int x, int y) { return x + y; }
int p3(int x, int y, int z) { return x + y + z; }
int p4(int x, int y, int z, int a) { return x + y + z + a; }
int p5(int x, int y, int z, int a, int b) { return x + y + z + a + b; }
private:
int x_;
};
static int getX(OverloadTest * u)
{
return u->x();
}
/************************************************************/
/* */
/* classes to test base declarations and conversions */
/* */
/************************************************************/
struct Dummy
{
virtual ~Dummy() {}
int dummy_;
};
struct Base
{
virtual int x() const { return 999; };
virtual ~Base() {}
};
// inherit Dummy so that the Base part of Concrete starts at an offset
// otherwise, typecast tests wouldn't be very meaningful
struct Derived1 : public Dummy, public Base
{
Derived1(int x): x_(x) {}
virtual int x() const { return x_; }
private:
int x_;
};
struct Derived2 : public Dummy, public Base
{
Derived2(int x): x_(x) {}
virtual int x() const { return x_; }
private:
int x_;
};
static int testUpcast(Base * b)
{
return b->x();
}
static std::auto_ptr<Base> derived1Factory(int i)
{
return std::auto_ptr<Base>(new Derived1(i));
}
static std::auto_ptr<Base> derived2Factory(int i)
{
return std::auto_ptr<Base>(new Derived2(i));
}
static int testDowncast1(Derived1 * d)
{
return d->x();
}
static int testDowncast2(Derived2 * d)
{
return d->x();
}
/************************************************************/
/* */
/* test classes for interaction of overloading, */
/* base declarations, and callbacks */
/* */
/************************************************************/
struct CallbackTestBase
{
virtual int testCallback(int i) { return callback(i); }
virtual int callback(int i) = 0;
virtual ~CallbackTestBase() {}
};
struct CallbackTest : public CallbackTestBase
{
virtual int callback(int i) { return i + 1; }
virtual std::string callbackString(std::string const & i) { return i + " 1"; }
};
struct CallbackTestCallback : public CallbackTest
{
CallbackTestCallback(PyObject* self)
: m_self(self)
{}
int callback(int x)
{
return py::Callback<int>::call_method(m_self, "callback", x);
}
std::string callbackString(std::string const & x)
{
return py::Callback<std::string>::call_method(m_self, "callback", x);
}
static int default_callback(CallbackTest * self, int x)
{
return self->CallbackTest::callback(x);
}
static std::string default_callbackString(CallbackTest * self, std::string x)
{
return self->CallbackTest::callbackString(x);
}
PyObject * m_self;
};
int testCallback(CallbackTestBase * b, int i)
{
return b->testCallback(i);
}
typedef boost::rational<int> 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 <class T>
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<T>()(x, y) ? -1 : std::less<T>()(y, x) ? 1 : 0; }
};
/************************************************************/
/* */
/* init the module */
/* */
/************************************************************/
void init_module(py::Module& m)
{
m.add(new Foo::PythonClass);
@@ -309,6 +549,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<boost::rational<int> > rational(m, "Rational");
rational.def(py::Constructor<int, int>());
rational.def(py::Constructor<int>());
rational.def(py::Constructor<>());
rational.def(StandardOps<Ratio>::add, "__add__");
rational.def(StandardOps<Ratio>::sub, "__sub__");
rational.def(StandardOps<Ratio>::mul, "__mul__");
rational.def(StandardOps<Ratio>::div, "__div__");
rational.def(StandardOps<Ratio>::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> range(m, "Range");
range.def(py::Constructor<int>());
range.def(py::Constructor<int, int>());
@@ -321,6 +576,64 @@ void init_module(py::Module& m)
range.def(&range_hash, "__hash__");
range.def_readonly(&Range::m_start, "start");
range.def_readonly(&Range::m_finish, "finish");
m.def(&testVoid, "overloaded");
m.def(&testInt, "overloaded");
m.def(&testString, "overloaded");
m.def(&test2, "overloaded");
m.def(&test3, "overloaded");
m.def(&test4, "overloaded");
m.def(&test5, "overloaded");
py::ClassWrapper<OverloadTest> over(m, "OverloadTest");
over.def(py::Constructor<py::Void>());
over.def(py::Constructor<OverloadTest const &>());
over.def(py::Constructor<int>());
over.def(py::Constructor<int, int>());
over.def(py::Constructor<int, int, int>());
over.def(py::Constructor<int, int, int, int>());
over.def(py::Constructor<int, int, int, int, int>());
over.def(&getX, "getX");
over.def(&OverloadTest::setX, "setX");
over.def(&OverloadTest::x, "overloaded");
over.def(&OverloadTest::p1, "overloaded");
over.def(&OverloadTest::p2, "overloaded");
over.def(&OverloadTest::p3, "overloaded");
over.def(&OverloadTest::p4, "overloaded");
over.def(&OverloadTest::p5, "overloaded");
py::ClassWrapper<Base> base(m, "Base");
base.def(&Base::x, "x");
py::ClassWrapper<Derived1> derived1(m, "Derived1");
// this enables conversions between Base and Derived1
// and makes wrapped methods of Base available
derived1.declare_base(base);
derived1.def(py::Constructor<int>());
py::ClassWrapper<Derived2> derived2(m, "Derived2");
// don't enable downcast from Base to Derived2
derived2.declare_base(base, py::without_downcast);
derived2.def(py::Constructor<int>());
m.def(&testUpcast, "testUpcast");
m.def(&derived1Factory, "derived1Factory");
m.def(&derived2Factory, "derived2Factory");
m.def(&testDowncast1, "testDowncast1");
m.def(&testDowncast2, "testDowncast2");
py::ClassWrapper<CallbackTestBase> callbackTestBase(m, "CallbackTestBase");
callbackTestBase.def(&CallbackTestBase::testCallback, "testCallback");
m.def(&testCallback, "testCallback");
py::ClassWrapper<CallbackTest, CallbackTestCallback> callbackTest(m, "CallbackTest");
callbackTest.def(py::Constructor<py::Void>());
callbackTest.def(&CallbackTest::callback, "callback",
&CallbackTestCallback::default_callback);
callbackTest.def(&CallbackTest::callbackString, "callback",
&CallbackTestCallback::default_callbackString);
callbackTest.declare_base(callbackTestBase);
}
void init_module()

12
gcc.mak
View File

@@ -11,7 +11,15 @@ LIBSRC = \
LIBOBJ = $(LIBSRC:.cpp=.o)
OBJ = $(LIBOBJ) extclass_demo.o
ifeq "$(OS)" "Windows_NT"
PYTHON_LIB=c:/tools/python/libs/python15.lib
INC = -Ic:/cygnus/usr/include/g++-3 -Ic:/cygnus/usr/include -Ic:/boost -Ic:/tools/python/include
MODULE_EXTENSION=dll
else
INC = -I/home/koethe/include -I/home/koethe/C++/boost -I/home/koethe/python/include/python1.5
MODULE_EXTENSION=so
endif
%.o: %.cpp
g++ -fPIC $(INC) -c $*.cpp
@@ -23,11 +31,11 @@ INC = -I/home/koethe/include -I/home/koethe/C++/boost -I/home/koethe/python/incl
[ -s $@ ] || rm -f $@
demo: extclass_demo.o libpycpp.a
g++ -shared -o demomodule.so extclass_demo.o -L. -lpycpp
g++ -shared -o demomodule.$(MODULE_EXTENSION) $(PYTHON_LIB) extclass_demo.o -L. -lpycpp
python test_extclass.py
clean:
rm -rf *.o *.so *.a *.d *.pyc *.bak a.out
rm -rf *.o *.$(MODULE_EXTENSION) *.a *.d *.pyc *.bak a.out
libpycpp.a: $(LIBOBJ)
rm -f libpycpp.a

View File

@@ -86,21 +86,13 @@ static MethodStruct* enable_method(const MethodStruct* base, MemberPtr p, Fn f)
return const_cast<MethodStruct*>(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<TypeObjectBase*>(instance->ob_type)
->instance_repr(instance);
return (static_cast<TypeObjectBase*>(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 <class R>
R int_call(PyObject* instance, R (TypeObjectBase::*f)(PyObject*) const)
{
try
{
return static_cast<TypeObjectBase*>(instance->ob_type)
->instance_compare(instance, other);
return (static_cast<TypeObjectBase*>(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 <class A1>
PyObject* call(PyObject* instance, PyObject* (TypeObjectBase::*f)(PyObject*, A1) const, A1 a1)
{
try
{
return static_cast<TypeObjectBase*>(instance->ob_type)
->instance_str(instance);
return (static_cast<TypeObjectBase*>(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 <class A1>
int call(PyObject* instance, int (TypeObjectBase::*f)(PyObject*, A1) const, A1 a1)
{
try
{
return static_cast<TypeObjectBase*>(instance->ob_type)
->instance_hash(instance);
return (static_cast<TypeObjectBase*>(instance->ob_type)->*f)(instance, a1);
}
catch(...)
{
handle_exception();
return -1;
}
}
template <class A1, class A2>
PyObject* call(PyObject* instance, PyObject* (TypeObjectBase::*f)(PyObject*, A1, A2) const, A1 a1, A2 a2)
{
try
{
return (static_cast<TypeObjectBase*>(instance->ob_type)->*f)(instance, a1, a2);
}
catch(...)
{
handle_exception();
return 0;
}
}
template <class A1, class A2>
int call(PyObject* instance, int (TypeObjectBase::*f)(PyObject*, A1, A2) const, A1 a1, A2 a2)
{
try
{
return (static_cast<TypeObjectBase*>(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 <class A1, class A2, class A3>
int call(PyObject* instance, int (TypeObjectBase::*f)(PyObject*, A1, A2, A3) const, A1 a1, A2 a2, A3 a3)
{
try
{
return static_cast<TypeObjectBase*>(instance->ob_type)
->instance_call(instance, args, keywords);
return (static_cast<TypeObjectBase*>(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<TypeObjectBase*>(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<TypeObjectBase*>(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<TypeObjectBase*>(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<TypeObjectBase*>(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<TypeObjectBase*>(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<TypeObjectBase*>(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<TypeObjectBase*>(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<TypeObjectBase*>(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<TypeObjectBase*>(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<TypeObjectBase*>(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<TypeObjectBase*>(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<TypeObjectBase*>(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 <std::size_t> 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()
{
}

View File

@@ -30,6 +30,8 @@
namespace py {
class InstanceHolderBase;
class TypeObjectBase : public PythonType
{
public:
@@ -42,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);
@@ -75,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 <class T>

View File

@@ -13,6 +13,7 @@
# include "pyconfig.h"
# include "pyptr.h"
# include "boost/operators.hpp"
# include <utility>
namespace py {
@@ -36,8 +37,31 @@ class Tuple : public Object
public:
Tuple(std::size_t n = 0);
explicit Tuple(Ptr p);
template <class First, class Second>
Tuple(const std::pair<First,Second>& 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 <class First, class Second>
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 <class First, class Second, class Third>
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);

23
py.cpp
View File

@@ -7,7 +7,11 @@
// producing this work.
#include "py.h"
#include <boost/cast.hpp>
#include <boost/config.hpp>
#include <typeinfo>
#ifndef BOOST_NO_LIMITS
# include <boost/cast.hpp>
#endif
namespace py {
@@ -82,11 +86,19 @@ T integer_from_python(PyObject* p, py::Type<T>)
{
const long long_result = from_python(p, py::Type<long>());
#ifndef BOOST_NO_LIMITS
try
{
return boost::numeric_cast<T>(long_result);
}
catch(const boost::bad_numeric_cast&)
#else
if (static_cast<T>(long_result) == long_result)
{
return static_cast<T>(long_result);
}
else
#endif
{
char buffer[256];
const char message[] = "%ld out of range for %s";
@@ -103,12 +115,17 @@ template <class T>
PyObject* integer_to_python(T value)
{
long value_as_long;
#ifndef BOOST_NO_LIMITS
try
{
value_as_long = boost::numeric_cast<T>(value);
value_as_long = boost::numeric_cast<long>(value);
}
catch(const boost::bad_numeric_cast&)
#else
value_as_long = static_cast<long>(value);
if (value_as_long != value)
#endif
{
const char message[] = "value out of range for Python int";
PyErr_SetString(PyExc_ValueError, message);

5
py.h
View File

@@ -165,6 +165,11 @@ PyObject* to_python(boost::shared_ptr<T> p)
// inline implementations
//
inline PyObject* to_python(double d)
{
return PyFloat_FromDouble(d);
}
inline PyObject* to_python(long l)
{
return PyInt_FromLong(l);

View File

@@ -18,12 +18,12 @@
Python.
<p>
The source code for py_cpp, including a MSVC demo project is available
<a href="py_cpp_20001015.zip">here</a>. It has been tested against Python
<a href="py_cpp_20001018.zip">here</a>. It has been tested against Python
1.5.2 with GCC 2.95.2, Metrowerks CodeWarrior Pro6 and with Microsoft
Visual C++ 6 sp4 using both the <a href="http://www.stlport.org">
STLport</a> standard library implementation <em>and</em> the library
implementation which ships with the compiler. It has also been tested
against Python 2.0c1 with an unknown version of MSVC++ by Alex Martelli.
against Python 2.0c1 with MSVC++ 6sp4 by Alex Martelli.
Py_cpp requires the <a href="http://www.boost.org">Boost</a> libraries,
and is currently under formal review on <a href=
"http://www.egroups.com/list/boost">the boost mailing list</a> for
@@ -116,5 +116,5 @@
express or implied warranty, and with no claim as to its suitability for
any purpose.
<p>
Updated: Oct 15, 2000
Updated: Oct 18, 2000

Binary file not shown.

View File

@@ -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 <name> 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<void>::call_method(this, "__setslice__", start, finish, value);
}
PyObject* Instance::add(PyObject* other)
{
return Callback<PyObject*>::call_method(this, "__add__", other);
}
PyObject* Instance::subtract(PyObject* other)
{
return Callback<PyObject*>::call_method(this, "__sub__", other);
}
PyObject* Instance::multiply(PyObject* other)
{
return Callback<PyObject*>::call_method(this, "__mul__", other);
}
PyObject* Instance::divide(PyObject* other)
{
return Callback<PyObject*>::call_method(this, "__div__", other);
}
PyObject* Instance::remainder(PyObject* other)
{
return Callback<PyObject*>::call_method(this, "__mod__", other);
}
PyObject* Instance::divmod(PyObject* other)
{
return Callback<PyObject*>::call_method(this, "__divmod__", other);
}
PyObject* Instance::power(PyObject* exponent, PyObject* modulus)
{
if (as_object(modulus->ob_type) == Py_None)
return Callback<PyObject*>::call_method(this, "__pow__", exponent);
else
return Callback<PyObject*>::call_method(this, "__pow__", exponent, modulus);
}
PyObject* Instance::negative()
{
return Callback<PyObject*>::call_method(this, "__neg__");
}
PyObject* Instance::positive()
{
return Callback<PyObject*>::call_method(this, "__pos__");
}
PyObject* Instance::absolute()
{
return Callback<PyObject*>::call_method(this, "__abs__");
}
int Instance::nonzero()
{
return Callback<bool>::call_method(this, "__nonzero__");
}
PyObject* Instance::invert()
{
return Callback<PyObject*>::call_method(this, "__invert__");
}
PyObject* Instance::lshift(PyObject* other)
{
return Callback<PyObject*>::call_method(this, "__lshift__", other);
}
PyObject* Instance::rshift(PyObject* other)
{
return Callback<PyObject*>::call_method(this, "__rshift__", other);
}
PyObject* Instance::do_and(PyObject* other)
{
return Callback<PyObject*>::call_method(this, "__and__", other);
}
PyObject* Instance::do_xor(PyObject* other)
{
return Callback<PyObject*>::call_method(this, "__xor__", other);
}
PyObject* Instance::do_or(PyObject* other)
{
return Callback<PyObject*>::call_method(this, "__or__", other);
}
int Instance::coerce(PyObject** x, PyObject** y)
{
assert(this == *x);
// Coerce must return a tuple
Tuple result(Callback<Tuple>::call_method(this, "__coerce__", *y));
*x = result[0].release();
*y = result[1].release();
return 0;
}
PyObject* Instance::as_int()
{
return Callback<PyObject*>::call_method(this, "__int__");
}
PyObject* Instance::as_long()
{
return Callback<PyObject*>::call_method(this, "__long__");
}
PyObject* Instance::as_float()
{
return Callback<PyObject*>::call_method(this, "__float__");
}
PyObject* Instance::oct()
{
return Callback<PyObject*>::call_method(this, "__oct__");
}
PyObject* Instance::hex()
{
return Callback<PyObject*>::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)

View File

@@ -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&);
@@ -92,6 +117,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;
@@ -316,6 +366,144 @@ PyObject* Class<T>::instance_call(PyObject* instance, PyObject* args, PyObject*
return Downcast<T>(instance)->call(args, keywords);
}
template <class T>
PyObject* Class<T>::instance_number_add(PyObject* instance, PyObject* other) const
{
return Downcast<T>(instance)->add(other);
}
template <class T>
PyObject* Class<T>::instance_number_subtract(PyObject* instance, PyObject* other) const
{
return Downcast<T>(instance)->subtract(other);
}
template <class T>
PyObject* Class<T>::instance_number_multiply(PyObject* instance, PyObject* other) const
{
return Downcast<T>(instance)->multiply(other);
}
template <class T>
PyObject* Class<T>::instance_number_divide(PyObject* instance, PyObject* other) const
{
return Downcast<T>(instance)->divide(other);
}
template <class T>
PyObject* Class<T>::instance_number_remainder(PyObject* instance, PyObject* other) const
{
return Downcast<T>(instance)->remainder(other);
}
template <class T>
PyObject* Class<T>::instance_number_divmod(PyObject* instance, PyObject* other) const
{
return Downcast<T>(instance)->divmod(other);
}
template <class T>
PyObject* Class<T>::instance_number_power(PyObject* instance, PyObject* exponent, PyObject* modulus) const
{
return Downcast<T>(instance)->power(exponent, modulus);
}
template <class T>
PyObject* Class<T>::instance_number_negative(PyObject* instance) const
{
return Downcast<T>(instance)->negative();
}
template <class T>
PyObject* Class<T>::instance_number_positive(PyObject* instance) const
{
return Downcast<T>(instance)->positive();
}
template <class T>
PyObject* Class<T>::instance_number_absolute(PyObject* instance) const
{
return Downcast<T>(instance)->absolute();
}
template <class T>
int Class<T>::instance_number_nonzero(PyObject* instance) const
{
return Downcast<T>(instance)->nonzero();
}
template <class T>
PyObject* Class<T>::instance_number_invert(PyObject* instance) const
{
return Downcast<T>(instance)->invert();
}
template <class T>
PyObject* Class<T>::instance_number_lshift(PyObject* instance, PyObject* other) const
{
return Downcast<T>(instance)->lshift(other);
}
template <class T>
PyObject* Class<T>::instance_number_rshift(PyObject* instance, PyObject* other) const
{
return Downcast<T>(instance)->rshift(other);
}
template <class T>
PyObject* Class<T>::instance_number_and(PyObject* instance, PyObject* other) const
{
return Downcast<T>(instance)->do_and(other);
}
template <class T>
PyObject* Class<T>::instance_number_xor(PyObject* instance, PyObject* other) const
{
return Downcast<T>(instance)->do_xor(other);
}
template <class T>
PyObject* Class<T>::instance_number_or(PyObject* instance, PyObject* other) const
{
return Downcast<T>(instance)->do_or(other);
}
template <class T>
int Class<T>::instance_number_coerce(PyObject* instance, PyObject** x, PyObject** y) const
{
return Downcast<T>(instance)->coerce(x, y);
}
template <class T>
PyObject* Class<T>::instance_number_int(PyObject* instance) const
{
return Downcast<T>(instance)->as_int();
}
template <class T>
PyObject* Class<T>::instance_number_long(PyObject* instance) const
{
return Downcast<T>(instance)->as_long();
}
template <class T>
PyObject* Class<T>::instance_number_float(PyObject* instance) const
{
return Downcast<T>(instance)->as_float();
}
template <class T>
PyObject* Class<T>::instance_number_oct(PyObject* instance) const
{
return Downcast<T>(instance)->oct();
}
template <class T>
PyObject* Class<T>::instance_number_hex(PyObject* instance) const
{
return Downcast<T>(instance)->hex();
}
template <class T>
Dict& Class<T>::dict()
{

View File

@@ -130,7 +130,7 @@ But objects not derived from Bar cannot:
>>> baz.pass_bar(baz)
Traceback (innermost last):
...
TypeError: extension class 'Baz' is not derived from 'Bar'.
TypeError: extension class 'Baz' is not convertible into 'Bar'.
The clone function on Baz returns a smart pointer; we wrap it into an
ExtensionInstance and make it look just like any other Baz instance.
@@ -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):
@@ -412,6 +428,146 @@ Testing __call__:
0
>>> comparator(couple2, couple)
1
Testing overloaded free functions
>>> overloaded()
'Hello world!'
>>> overloaded(1)
1
>>> overloaded('foo')
'foo'
>>> overloaded(1,2)
3
>>> overloaded(1,2,3)
6
>>> overloaded(1,2,3,4)
10
>>> overloaded(1,2,3,4,5)
15
>>> try: overloaded(1, 'foo')
... except TypeError, err:
... assert re.match("No overloaded functions match \(int, string\)\. Candidates are:",
... str(err))
... else:
... print 'no exception'
Testing overloaded constructors
>>> over = OverloadTest()
>>> over.getX()
1000
>>> over = OverloadTest(1)
>>> over.getX()
1
>>> over = OverloadTest(1,1)
>>> over.getX()
2
>>> over = OverloadTest(1,1,1)
>>> over.getX()
3
>>> over = OverloadTest(1,1,1,1)
>>> over.getX()
4
>>> over = OverloadTest(1,1,1,1,1)
>>> over.getX()
5
>>> over = OverloadTest(over)
>>> over.getX()
5
>>> try: over = OverloadTest(1, 'foo')
... except TypeError, err:
... assert re.match("No overloaded functions match \(OverloadTest, int, string\)\. Candidates are:",
... str(err))
... else:
... print 'no exception'
Testing overloaded methods
>>> over.setX(3)
>>> over.overloaded()
3
>>> over.overloaded(1)
1
>>> over.overloaded(1,1)
2
>>> over.overloaded(1,1,1)
3
>>> over.overloaded(1,1,1,1)
4
>>> over.overloaded(1,1,1,1,1)
5
>>> try: over.overloaded(1,'foo')
... except TypeError, err:
... assert re.match("No overloaded functions match \(OverloadTest, int, string\)\. Candidates are:",
... str(err))
... else:
... print 'no exception'
Testing base class conversions
>>> testUpcast(over)
Traceback (innermost last):
TypeError: extension class 'OverloadTest' is not convertible into 'Base'.
>>> der1 = Derived1(333)
>>> der1.x()
333
>>> testUpcast(der1)
333
>>> der1 = derived1Factory(1000)
>>> testDowncast1(der1)
1000
>>> testDowncast2(der1)
Traceback (innermost last):
TypeError: extension class 'Base' is not convertible into 'Derived2'.
>>> der2 = Derived2(444)
>>> der2.x()
444
>>> testUpcast(der2)
444
>>> der2 = derived2Factory(1111)
>>> testDowncast2(der2)
Traceback (innermost last):
TypeError: extension class 'Base' is not convertible into 'Derived2'.
Testing interaction between callbacks, base declarations, and overloading
- testCallback() calls callback() (within C++)
- callback() is overloaded (in the wrapped class CallbackTest)
- callback() is redefined in RedefineCallback (overloading is simulated by type casing)
- testCallback() should use the redefined callback()
>>> c = CallbackTest()
>>> c.testCallback(1)
2
>>> c.testCallback('foo')
Traceback (innermost last):
File "<stdin>", line 1, in ?
TypeError: illegal argument type for built-in operation
>>> c.callback(1)
2
>>> c.callback('foo')
'foo 1'
>>> import types
>>> class RedefineCallback(CallbackTest):
... def callback(self, x):
... if type(x) is types.IntType:
... return x - 2
... else:
... return CallbackTest.callback(self,x)
...
>>> r = RedefineCallback()
>>> r.callback(1)
-1
>>> r.callback('foo')
'foo 1'
>>> r.testCallback('foo')
Traceback (innermost last):
File "<stdin>", line 1, in ?
TypeError: illegal argument type for built-in operation
>>> r.testCallback(1)
-1
>>> testCallback(r, 1)
-1
'''
from demo import *

View File

@@ -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<Derived> 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

BIN
vc6_prj/vc6_prj.opt Normal file

Binary file not shown.