Author: Wim Lavrijsen <wlavrij...@lbl.gov> Branch: reflex-support Changeset: r44615:7e43dd48bcb1 Date: 2011-05-31 13:19 -0700 http://bitbucket.org/pypy/pypy/changeset/7e43dd48bcb1/
Log: pull C++ bound methods into the app level to allow normal python mro to work diff --git a/pypy/module/cppyy/interp_cppyy.py b/pypy/module/cppyy/interp_cppyy.py --- a/pypy/module/cppyy/interp_cppyy.py +++ b/pypy/module/cppyy/interp_cppyy.py @@ -332,17 +332,26 @@ @jit.purefunction def get_overload(self, name): - return self.methods[name] + try: + return self.methods[name] + except KeyError: + raise OperationError( + self.space.w_AttributeError, + self.space.wrap(str("class %s has no attribute %s" % (self.name, name)))) def get_data_member_names(self): return self.space.newlist([self.space.wrap(name) for name in self.data_members]) @jit.purefunction def get_data_member(self, name): - return self.data_members[name] + try: + return self.data_members[name] + except KeyError: + raise OperationError( + self.space.w_AttributeError, + self.space.wrap(str("class %s has no attribute %s" % (self.name, name)))) - def invoke(self, name, args_w): - overload = self.get_overload(name) + def invoke(self, overload, args_w): return overload.call(NULL_VOIDP, args_w) W_CPPScope.typedef = TypeDef( @@ -351,7 +360,7 @@ get_overload = interp2app(W_CPPScope.get_overload, unwrap_spec=['self', str]), get_data_member_names = interp2app(W_CPPScope.get_data_member_names, unwrap_spec=['self']), get_data_member = interp2app(W_CPPScope.get_data_member, unwrap_spec=['self', str]), - invoke = interp2app(W_CPPScope.invoke, unwrap_spec=['self', str, 'args_w']), + invoke = interp2app(W_CPPScope.invoke, unwrap_spec=['self', W_CPPOverload, 'args_w']), ) @@ -443,7 +452,7 @@ get_data_member_names = interp2app(W_CPPType.get_data_member_names, unwrap_spec=['self']), get_data_member = interp2app(W_CPPType.get_data_member, unwrap_spec=['self', str]), is_namespace = interp2app(W_CPPType.is_namespace, unwrap_spec=['self']), - invoke = interp2app(W_CPPType.invoke, unwrap_spec=['self', str, 'args_w']), + invoke = interp2app(W_CPPType.invoke, unwrap_spec=['self', W_CPPOverload, 'args_w']), construct = interp2app(W_CPPType.construct, unwrap_spec=['self', 'args_w']), ) @@ -460,10 +469,9 @@ if not self.rawobject: raise OperationError(self.space.w_ReferenceError, self.space.wrap("trying to access a NULL pointer")) - def invoke(self, method_name, args_w): + def invoke(self, overload, args_w): self._nullcheck() cppclass = jit.hint(self.cppclass, promote=True) - overload = cppclass.get_overload(method_name) return overload.call(self.rawobject, args_w) def destruct(self): @@ -472,6 +480,6 @@ W_CPPInstance.typedef = TypeDef( 'CPPInstance', - invoke = interp2app(W_CPPInstance.invoke, unwrap_spec=['self', str, 'args_w']), + invoke = interp2app(W_CPPInstance.invoke, unwrap_spec=['self', W_CPPOverload, 'args_w']), destruct = interp2app(W_CPPInstance.destruct, unwrap_spec=['self']), ) diff --git a/pypy/module/cppyy/pythonify.py b/pypy/module/cppyy/pythonify.py --- a/pypy/module/cppyy/pythonify.py +++ b/pypy/module/cppyy/pythonify.py @@ -29,27 +29,28 @@ bound_obj._cppinstance = cppobj return bound_obj -def make_static_function(cpptype, name, rettype): - print rettype +def make_static_function(cpptype, func_name, cppol): + rettype = cppol.get_returntype() if not rettype: # return builtin type def method(*args): - return cpptype.invoke(name, *args) + return cpptype.invoke(cppol, *args) else: # return instance cppclass = get_cppclass(rettype) def method(*args): - return bind_object(cpptype.invoke(name, *args), cppclass) - method.__name__ = name + return bind_object(cpptype.invoke(cppol, *args), cppclass) + method.__name__ = func_name return staticmethod(method) -def make_method(name, rettype): +def make_method(meth_name, cppol): + rettype = cppol.get_returntype() if not rettype: # return builtin type def method(self, *args): - return self._cppinstance.invoke(name, *args) + return self._cppinstance.invoke(cppol, *args) else: # return instance cppclass = get_cppclass(rettype) def method(self, *args): - return bind_object(self._cppinstance.invoke(name, *args), cppclass) - method.__name__ = name + return bind_object(self._cppinstance.invoke(cppol, *args), cppclass) + method.__name__ = meth_name return method @@ -68,9 +69,9 @@ d = {} # insert static methods into the "namespace" dictionary - for f in cppns.get_method_names(): + for func_name in cppns.get_method_names(): cppol = cppns.get_overload(f) - d[f] = make_static_function(cppns, f, cppol.get_returntype()) + d[func_name] = make_static_function(cppns, func_name, cppol) # create a meta class to allow properties (for static data write access) metans = type(CppyyNamespace)(name+'_meta', (type(type),), @@ -90,16 +91,16 @@ _existing_cppitems[name] = pycppns return pycppns -def make_cppclass(name, cpptype): +def make_cppclass(class_name, cpptype): d = {"_cppyyclass" : cpptype} # insert (static) methods into the class dictionary - for f in cpptype.get_method_names(): - cppol = cpptype.get_overload(f) + for meth_name in cpptype.get_method_names(): + cppol = cpptype.get_overload(meth_name) if cppol.is_static(): - d[f] = make_static_function(cpptype, f, cppol.get_returntype()) + d[meth_name] = make_static_function(cpptype, meth_name, cppol) else: - d[f] = make_method(f, cppol.get_returntype()) + d[meth_name] = make_method(meth_name, cppol) # get a list of base classes for class creation bases = tuple([get_cppclass(base) for base in cpptype.get_base_names()]) @@ -108,23 +109,23 @@ # create a meta class to allow properties (for static data write access) metabases = tuple([type(base) for base in bases]) - metacpp = type(CppyyClass)(name+'_meta', metabases, + metacpp = type(CppyyClass)(class_name+'_meta', metabases, {"__getattr__" : __innercpp_getattr__}) # add all data members to the dictionary of the class to be created, and # static ones also to the meta class (needed for property setters) - for dm in cpptype.get_data_member_names(): - cppdm = cpptype.get_data_member(dm) + for dm_name in cpptype.get_data_member_names(): + cppdm = cpptype.get_data_member(dm_name) - d[dm] = cppdm + d[dm_name] = cppdm if cppdm.is_static(): - setattr(metacpp, dm, cppdm) + setattr(metacpp, dm_name, cppdm) # create the python-side C++ class representation - pycpptype = metacpp(name, bases, d) + pycpptype = metacpp(class_name, bases, d) # cache result and return - _existing_cppitems[name] = pycpptype + _existing_cppitems[class_name] = pycpptype return pycpptype diff --git a/pypy/module/cppyy/test/advancedcpp.h b/pypy/module/cppyy/test/advancedcpp.h --- a/pypy/module/cppyy/test/advancedcpp.h +++ b/pypy/module/cppyy/test/advancedcpp.h @@ -4,23 +4,25 @@ //=========================================================================== class base_class { // for simple inheritance testing public: - base_class() { m_a = 1; m_da = 1.1; } + base_class() { m_b = 1; m_db = 1.1; } virtual ~base_class() {} - virtual int get_value() = 0; + virtual int get_value() { return m_b; } + double get_base_value() { return m_db; } public: - int m_a; - double m_da; + int m_b; + double m_db; }; class derived_class : public base_class { public: - derived_class() { m_b = 2; m_db = 2.2;} - virtual int get_value() { return m_b; } + derived_class() { m_d = 2; m_dd = 2.2;} + virtual int get_value() { return m_d; } + double get_derived_value() { return m_dd; } public: - int m_b; - double m_db; + int m_d; + double m_dd; }; diff --git a/pypy/module/cppyy/test/bench1.py b/pypy/module/cppyy/test/bench1.py --- a/pypy/module/cppyy/test/bench1.py +++ b/pypy/module/cppyy/test/bench1.py @@ -10,11 +10,14 @@ for i in range(10000000): i +addDataToInt = cls.get_overload("addDataToInt") + def f(): res = 0 for i in range(10000000): - #inst.invoke("addDataToDouble", float(i)) - inst.invoke("addDataToInt", i) + #inst.invoke(cls.get_overload("addDataToDouble"), float(i)) + #inst.invoke(cls.get_overload("addDataToInt"), i) + inst.invoke(addDataToInt, i) g(); f(); t1 = time.time() diff --git a/pypy/module/cppyy/test/test_advancedcpp.py b/pypy/module/cppyy/test/test_advancedcpp.py --- a/pypy/module/cppyy/test/test_advancedcpp.py +++ b/pypy/module/cppyy/test/test_advancedcpp.py @@ -33,11 +33,22 @@ assert issubclass(derived_class, base_class) assert not issubclass(base_class, derived_class) - c = derived_class() - assert isinstance( c, derived_class ) - assert isinstance( c, base_class ) + b = base_class() + assert isinstance(b, base_class) + assert not isinstance(b, derived_class) - c.destruct() + assert b.get_value() == 1 + assert b.get_base_value() == 1.1 + + d = derived_class() + assert isinstance(d, derived_class) + assert isinstance(d, base_class) + + assert d.get_value() == 2 + assert d.get_base_value() == 1.1 + assert d.get_derived_value() == 2.2 + + d.destruct() def test02_namespaces(self): """Test access to namespaces and inner classes""" diff --git a/pypy/module/cppyy/test/test_cppyy.py b/pypy/module/cppyy/test/test_cppyy.py --- a/pypy/module/cppyy/test/test_cppyy.py +++ b/pypy/module/cppyy/test/test_cppyy.py @@ -39,136 +39,143 @@ def test_example01static_int(self): """Test passing of an int, returning of an int, and overloading on a differening number of arguments.""" + import sys t = self.example01 - res = t.invoke("staticAddOneToInt", 1) + + res = t.invoke(t.get_overload("staticAddOneToInt"), 1) assert res == 2 - res = t.invoke("staticAddOneToInt", 1L) + res = t.invoke(t.get_overload("staticAddOneToInt"), 1L) assert res == 2 - res = t.invoke("staticAddOneToInt", 1, 2) + res = t.invoke(t.get_overload("staticAddOneToInt"), 1, 2) assert res == 4 - res = t.invoke("staticAddOneToInt", -1) + res = t.invoke(t.get_overload("staticAddOneToInt"), -1) assert res == 0 - res = t.invoke("staticAddOneToInt", sys.maxint-1) + res = t.invoke(t.get_overload("staticAddOneToInt"), sys.maxint-1) assert res == sys.maxint - res = t.invoke("staticAddOneToInt", sys.maxint) + res = t.invoke(t.get_overload("staticAddOneToInt"), sys.maxint) assert res == -sys.maxint-1 - raises(TypeError, 't.invoke("staticAddOneToInt", 1, [])') - raises(TypeError, 't.invoke("staticAddOneToInt", 1.)') - raises(OverflowError, 't.invoke("staticAddOneToInt", sys.maxint+1)') + raises(TypeError, 't.invoke(t.get_overload("staticAddOneToInt"), 1, [])') + raises(TypeError, 't.invoke(t.get_overload("staticAddOneToInt"), 1.)') + raises(OverflowError, 't.invoke(t.get_overload("staticAddOneToInt"), sys.maxint+1)') def test_example01static_double(self): """Test passing of a double and returning of a double on a static function.""" + t = self.example01 - res = t.invoke("staticAddToDouble", 0.09) + + res = t.invoke(t.get_overload("staticAddToDouble"), 0.09) assert res == 0.09 + 0.01 def test_example01static_constcharp(self): """Test passing of a C string and returning of a C string on a static function.""" + t = self.example01 - res = t.invoke("staticAtoi", "1") + + res = t.invoke(t.get_overload("staticAtoi"), "1") assert res == 1 - - res = t.invoke("staticStrcpy", "aap") + res = t.invoke(t.get_overload("staticStrcpy"), "aap") + assert res == "aap" + res = t.invoke(t.get_overload("staticStrcpy"), u"aap") assert res == "aap" - res = t.invoke("staticStrcpy", u"aap") - assert res == "aap" - - raises(TypeError, 't.invoke("staticStrcpy", 1.)') + raises(TypeError, 't.invoke(t.get_overload("staticStrcpy"), 1.)') def test_example01method_int(self): """Test passing of a int, returning of a int, and memory cleanup, on a method.""" + t = self.example01 - assert t.invoke("getCount") == 0 - instance = t.construct(7) - assert t.invoke("getCount") == 1 - res = instance.invoke("addDataToInt", 4) + + assert t.invoke(t.get_overload("getCount")) == 0 + + e1 = t.construct(7) + assert t.invoke(t.get_overload("getCount")) == 1 + res = e1.invoke(t.get_overload("addDataToInt"), 4) assert res == 11 - res = instance.invoke("addDataToInt", -4) + res = e1.invoke(t.get_overload("addDataToInt"), -4) assert res == 3 - instance.destruct() - assert t.invoke("getCount") == 0 - raises(ReferenceError, 'instance.invoke("addDataToInt", 4)') + e1.destruct() + assert t.invoke(t.get_overload("getCount")) == 0 + raises(ReferenceError, 'e1.invoke(t.get_overload("addDataToInt"), 4)') - instance = t.construct(7) - instance2 = t.construct(8) - assert t.invoke("getCount") == 2 - instance.destruct() - assert t.invoke("getCount") == 1 - instance2.destruct() - assert t.invoke("getCount") == 0 + e1 = t.construct(7) + e2 = t.construct(8) + assert t.invoke(t.get_overload("getCount")) == 2 + e1.destruct() + assert t.invoke(t.get_overload("getCount")) == 1 + e2.destruct() + assert t.invoke(t.get_overload("getCount")) == 0 def test_example01method_double(self): """Test passing of a double and returning of double on a method""" + t = self.example01 - instance = t.construct(13) - res = instance.invoke("addDataToDouble", 16) + + e = t.construct(13) + res = e.invoke(t.get_overload("addDataToDouble"), 16) assert round(res-29, 8) == 0. - instance.destruct() - instance = t.construct(-13) - res = instance.invoke("addDataToDouble", 16) + e.destruct() + + e = t.construct(-13) + res = e.invoke(t.get_overload("addDataToDouble"), 16) assert round(res-3, 8) == 0. - instance.destruct() - assert t.invoke("getCount") == 0 + e.destruct() + assert t.invoke(t.get_overload("getCount")) == 0 def test_example01method_constcharp(self): """Test passing of a C string and returning of a C string on a method.""" t = self.example01 - instance = t.construct(42) - res = instance.invoke("addDataToAtoi", "13") + e = t.construct(42) + res = e.invoke(t.get_overload("addDataToAtoi"), "13") assert res == 55 - - res = instance.invoke("addToStringValue", "12") + res = e.invoke(t.get_overload("addToStringValue"), "12") assert res == "54" - res = instance.invoke("addToStringValue", "-12") + res = e.invoke(t.get_overload("addToStringValue"), "-12") assert res == "30" - instance.destruct() - assert t.invoke("getCount") == 0 + e.destruct() + assert t.invoke(t.get_overload("getCount")) == 0 def testPassingOfAnObjectByPointer(self): """Test passing of an instance as an argument.""" - t = self.example01 + t1 = self.example01 + t2 = self.payload - pl = self.payload.construct(3.14) - assert round(pl.invoke("getData")-3.14, 8) == 0 - - t.invoke("staticSetPayload", pl, 41.) # now pl is a CPPInstance - assert pl.invoke("getData") == 41. + pl = t2.construct(3.14) + assert round(pl.invoke(t2.get_overload("getData"))-3.14, 8) == 0 + t1.invoke(t1.get_overload("staticSetPayload"), pl, 41.) # now pl is a CPPInstance + assert pl.invoke(t2.get_overload("getData")) == 41. - e = t.construct(50) - e.invoke("setPayload", pl); - assert round(pl.invoke("getData")-50., 8) == 0 + e = t1.construct(50) + e.invoke(t1.get_overload("setPayload"), pl); + assert round(pl.invoke(t2.get_overload("getData"))-50., 8) == 0 e.destruct() pl.destruct() - assert t.invoke("getCount") == 0 + assert t1.invoke(t1.get_overload("getCount")) == 0 def testReturningOfAnObjectByPointer(self): """Test returning of an instance as an argument.""" - t = self.example01 - - pl = self.payload.construct(3.14) - assert round(pl.invoke("getData")-3.14, 8) == 0 + t1 = self.example01 + t2 = self.payload - pl2 = t.invoke("staticCyclePayload", pl, 38.) - assert pl2.invoke("getData") == 38. + pl1 = t2.construct(3.14) + assert round(pl1.invoke(t2.get_overload("getData"))-3.14, 8) == 0 + pl2 = t1.invoke(t1.get_overload("staticCyclePayload"), pl1, 38.) + assert pl2.invoke(t2.get_overload("getData")) == 38. - e = t.construct(50) - - pl2 = e.invoke("cyclePayload", pl); - assert round(pl2.invoke("getData")-50., 8) == 0 + e = t1.construct(50) + pl2 = e.invoke(t1.get_overload("cyclePayload"), pl1); + assert round(pl2.invoke(t2.get_overload("getData"))-50., 8) == 0 e.destruct() - pl.destruct() - assert t.invoke("getCount") == 0 - + pl1.destruct() + assert t1.invoke(t1.get_overload("getCount")) == 0 _______________________________________________ pypy-commit mailing list pypy-commit@python.org http://mail.python.org/mailman/listinfo/pypy-commit