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:
@@ -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;
|
||||
};
|
||||
|
||||
@@ -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
|
||||
|
||||
62
extclass.cpp
62
extclass.cpp
@@ -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);
|
||||
|
||||
181
extclass.h
181
extclass.h
@@ -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
|
||||
|
||||
|
||||
@@ -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
12
gcc.mak
@@ -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
|
||||
|
||||
522
newtypes.cpp
522
newtypes.cpp
@@ -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()
|
||||
{
|
||||
}
|
||||
|
||||
37
newtypes.h
37
newtypes.h
@@ -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>
|
||||
|
||||
26
objects.h
26
objects.h
@@ -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
23
py.cpp
@@ -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
5
py.h
@@ -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);
|
||||
|
||||
@@ -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.
160
subclass.cpp
160
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 <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)
|
||||
|
||||
190
subclass.h
190
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&);
|
||||
@@ -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()
|
||||
{
|
||||
|
||||
158
test_extclass.py
158
test_extclass.py
@@ -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 *
|
||||
|
||||
6
todo.txt
6
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<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
BIN
vc6_prj/vc6_prj.opt
Normal file
Binary file not shown.
Reference in New Issue
Block a user