Author: Philip Jenvey <pjen...@underboss.org> Branch: py3k Changeset: r70952:e0ce5503a026 Date: 2014-04-24 16:58 -0700 http://bitbucket.org/pypy/pypy/changeset/e0ce5503a026/
Log: merge default (ea86924e88fb) diff --git a/lib-python/2.7/test/test_itertools.py b/lib-python/2.7/test/test_itertools.py --- a/lib-python/2.7/test/test_itertools.py +++ b/lib-python/2.7/test/test_itertools.py @@ -139,7 +139,6 @@ @test_support.impl_detail("tuple reuse is specific to CPython") def test_combinations_tuple_reuse(self): - # Test implementation detail: tuple re-use self.assertEqual(len(set(map(id, combinations('abcde', 3)))), 1) self.assertNotEqual(len(set(map(id, list(combinations('abcde', 3))))), 1) @@ -211,7 +210,6 @@ @test_support.impl_detail("tuple reuse is specific to CPython") def test_combinations_with_replacement_tuple_reuse(self): - # Test implementation detail: tuple re-use cwr = combinations_with_replacement self.assertEqual(len(set(map(id, cwr('abcde', 3)))), 1) self.assertNotEqual(len(set(map(id, list(cwr('abcde', 3))))), 1) @@ -278,7 +276,6 @@ @test_support.impl_detail("tuple reuse is specific to CPython") def test_permutations_tuple_reuse(self): - # Test implementation detail: tuple re-use self.assertEqual(len(set(map(id, permutations('abcde', 3)))), 1) self.assertNotEqual(len(set(map(id, list(permutations('abcde', 3))))), 1) diff --git a/pypy/doc/cppyy.rst b/pypy/doc/cppyy.rst --- a/pypy/doc/cppyy.rst +++ b/pypy/doc/cppyy.rst @@ -560,6 +560,12 @@ Fixing these bootstrap problems is on the TODO list. The global namespace is ``cppyy.gbl``. +* **NULL**: Is represented as ``cppyy.gbl.nullptr``. + In C++11, the keyword ``nullptr`` is used to represent ``NULL``. + For clarity of intent, it is recommended to use this instead of ``None`` + (or the integer ``0``, which can serve in some cases), as ``None`` is better + understood as ``void`` in C++. + * **operator conversions**: If defined in the C++ class and a python equivalent exists (i.e. all builtin integer and floating point types, as well as ``bool``), it will map onto that python conversion. diff --git a/pypy/doc/extending.rst b/pypy/doc/extending.rst --- a/pypy/doc/extending.rst +++ b/pypy/doc/extending.rst @@ -66,58 +66,26 @@ Reflex ====== -This method is still experimental. It adds the `cppyy`_ module. -The method works by using the `Reflex package`_ to provide reflection -information of the C++ code, which is then used to automatically generate -bindings at runtime. -From a python standpoint, there is no difference between generating bindings -at runtime, or having them "statically" generated and available in scripts -or compiled into extension modules: python classes and functions are always -runtime structures, created when a script or module loads. +The builtin `cppyy`_ module uses reflection information, provided by +`Reflex`_ (which needs to be `installed separately`_), of C/C++ code to +automatically generate bindings at runtime. +In Python, classes and functions are always runtime structures, so when they +are generated matters not for performance. However, if the backend itself is capable of dynamic behavior, it is a much -better functional match to python, allowing tighter integration and more -natural language mappings. -Full details are `available here`_. +better functional match, allowing tighter integration and more natural +language mappings. + +The `cppyy`_ module is written in RPython, thus PyPy's JIT is able to remove +most cross-language call overhead. + +`Full details`_ are `available here`_. .. _`cppyy`: cppyy.html -.. _`reflex-support`: cppyy.html -.. _`Reflex package`: http://root.cern.ch/drupal/content/reflex +.. _`installed separately`: http://cern.ch/wlav/reflex-2013-08-14.tar.bz2 +.. _`Reflex`: http://root.cern.ch/drupal/content/reflex +.. _`Full details`: cppyy.html .. _`available here`: cppyy.html -Pros ----- - -The cppyy module is written in RPython, which makes it possible to keep the -code execution visible to the JIT all the way to the actual point of call into -C++, thus allowing for a very fast interface. -Reflex is currently in use in large software environments in High Energy -Physics (HEP), across many different projects and packages, and its use can be -virtually completely automated in a production environment. -One of its uses in HEP is in providing language bindings for CPython. -Thus, it is possible to use Reflex to have bound code work on both CPython and -on PyPy. -In the medium-term, Reflex will be replaced by `cling`_, which is based on -`llvm`_. -This will affect the backend only; the python-side interface is expected to -remain the same, except that cling adds a lot of dynamic behavior to C++, -enabling further language integration. - -.. _`cling`: http://root.cern.ch/drupal/content/cling -.. _`llvm`: http://llvm.org/ - -Cons ----- - -C++ is a large language, and cppyy is not yet feature-complete. -Still, the experience gained in developing the equivalent bindings for CPython -means that adding missing features is a simple matter of engineering, not a -question of research. -The module is written so that currently missing features should do no harm if -you don't use them, if you do need a particular feature, it may be necessary -to work around it in python or with a C++ helper function. -Although Reflex works on various platforms, the bindings with PyPy have only -been tested on Linux. - RPython Mixed Modules ===================== diff --git a/pypy/module/cppyy/src/dummy_backend.cxx b/pypy/module/cppyy/src/dummy_backend.cxx --- a/pypy/module/cppyy/src/dummy_backend.cxx +++ b/pypy/module/cppyy/src/dummy_backend.cxx @@ -38,6 +38,24 @@ typedef std::map<cppyy_scope_t, Cppyy_PseudoClassInfo> Scopes_t; static Scopes_t s_scopes; +class PseudoExample01 { +public: + PseudoExample01() : m_somedata(-99) {} + PseudoExample01(int a) : m_somedata(a) {} + PseudoExample01(const PseudoExample01& e) : m_somedata(e.m_somedata) {} + PseudoExample01& operator=(const PseudoExample01& e) { + if (this != &e) m_somedata = e.m_somedata; + return *this; + } + virtual ~PseudoExample01() {} + +public: + int m_somedata; +}; + +static int example01_last_static_method = 0; +static int example01_last_constructor = 0; + struct Cppyy_InitPseudoReflectionInfo { Cppyy_InitPseudoReflectionInfo() { // class example01 -- @@ -46,27 +64,62 @@ std::vector<Cppyy_PseudoMethodInfo> methods; - // static double staticAddToDouble(double a); + // ( 0) static double staticAddToDouble(double a) std::vector<std::string> argtypes; argtypes.push_back("double"); methods.push_back(Cppyy_PseudoMethodInfo("staticAddToDouble", argtypes, "double")); - // static int staticAddOneToInt(int a); - // static int staticAddOneToInt(int a, int b); + // ( 1) static int staticAddOneToInt(int a) + // ( 2) static int staticAddOneToInt(int a, int b) argtypes.clear(); argtypes.push_back("int"); methods.push_back(Cppyy_PseudoMethodInfo("staticAddOneToInt", argtypes, "int")); argtypes.push_back("int"); methods.push_back(Cppyy_PseudoMethodInfo("staticAddOneToInt", argtypes, "int")); - // static int staticAtoi(const char* str); + // ( 3) static int staticAtoi(const char* str) argtypes.clear(); argtypes.push_back("const char*"); methods.push_back(Cppyy_PseudoMethodInfo("staticAtoi", argtypes, "int")); - // static char* staticStrcpy(const char* strin); + // ( 4) static char* staticStrcpy(const char* strin) methods.push_back(Cppyy_PseudoMethodInfo("staticStrcpy", argtypes, "char*")); + // ( 5) static void staticSetPayload(payload* p, double d) + // ( 6) static payload* staticCyclePayload(payload* p, double d) + // ( 7) static payload staticCopyCyclePayload(payload* p, double d) + argtypes.clear(); + argtypes.push_back("payload*"); + argtypes.push_back("double"); + methods.push_back(Cppyy_PseudoMethodInfo("staticSetPayload", argtypes, "void")); + methods.push_back(Cppyy_PseudoMethodInfo("staticCyclePayload", argtypes, "payload*")); + methods.push_back(Cppyy_PseudoMethodInfo("staticCopyCyclePayload", argtypes, "payload")); + + // ( 8) static int getCount() + // ( 9) static void setCount(int) + argtypes.clear(); + methods.push_back(Cppyy_PseudoMethodInfo("getCount", argtypes, "int")); + argtypes.push_back("int"); + methods.push_back(Cppyy_PseudoMethodInfo("setCount", argtypes, "void")); + + // cut-off is used in cppyy_is_static + example01_last_static_method = methods.size(); + + // (10) example01() + // (11) example01(int a) + argtypes.clear(); + methods.push_back(Cppyy_PseudoMethodInfo("example01", argtypes, "constructor")); + argtypes.push_back("int"); + methods.push_back(Cppyy_PseudoMethodInfo("example01", argtypes, "constructor")); + + // cut-off is used in cppyy_is_constructor + example01_last_constructor = methods.size(); + + // (12) double addDataToDouble(double a) + argtypes.clear(); + argtypes.push_back("double"); + methods.push_back(Cppyy_PseudoMethodInfo("addDataToDouble", argtypes, "double")); + Cppyy_PseudoClassInfo info(methods); s_scopes[(cppyy_scope_t)s_scope_id] = info; // -- class example01 @@ -98,47 +151,69 @@ } +/* memory management ------------------------------------------------------ */ +void cppyy_destruct(cppyy_type_t handle, cppyy_object_t self) { + if (handle == s_handles["example01"]) + delete (PseudoExample01*)self; +} + + /* method/function dispatching -------------------------------------------- */ -template<typename T> -static inline T cppyy_call_T(cppyy_method_t method, cppyy_object_t self, int nargs, void* args) { - T result = T(); +int cppyy_call_i(cppyy_method_t method, cppyy_object_t self, int nargs, void* args) { + int result = 0; switch ((long)method) { - case 0: // double staticAddToDouble(double) - assert(!self && nargs == 1); - result = ((CPPYY_G__value*)args)[0].obj.d + 0.01; - break; - case 1: // int staticAddOneToInt(int) + case 1: // static int staticAddOneToInt(int) assert(!self && nargs == 1); result = ((CPPYY_G__value*)args)[0].obj.in + 1; break; - case 2: // int staticAddOneToInt(int, int) + case 2: // static int staticAddOneToInt(int, int) assert(!self && nargs == 2); result = ((CPPYY_G__value*)args)[0].obj.in + ((CPPYY_G__value*)args)[1].obj.in + 1; break; - case 3: // int staticAtoi(const char* str) + case 3: // static int staticAtoi(const char* str) assert(!self && nargs == 1); result = ::atoi((const char*)(*(long*)&((CPPYY_G__value*)args)[0])); break; + case 8: // static int getCount() + assert(!self && nargs == 0); + // can't actually call this method (would need to resolve example01::count), but + // other than the memory tests, most tests just check for 0 at the end + result = 0; + break; default: + assert(!"method unknown in cppyy_call_i"); break; } return result; } -int cppyy_call_i(cppyy_method_t method, cppyy_object_t self, int nargs, void* args) { - return cppyy_call_T<int>(method, self, nargs, args); -} - long cppyy_call_l(cppyy_method_t method, cppyy_object_t self, int nargs, void* args) { - // char* staticStrcpy(const char* strin) - const char* strin = (const char*)(*(long*)&((CPPYY_G__value*)args)[0]); - char* strout = (char*)malloc(::strlen(strin)+1); - ::strcpy(strout, strin); - return (long)strout; + if ((long)method == 4) { // static char* staticStrcpy(const char* strin) + const char* strin = (const char*)(*(long*)&((CPPYY_G__value*)args)[0]); + char* strout = (char*)malloc(::strlen(strin)+1); + ::strcpy(strout, strin); + return (long)strout; + } + assert(!"method unknown in cppyy_call_l"); + return 0; } double cppyy_call_d(cppyy_method_t method, cppyy_object_t self, int nargs, void* args) { - return cppyy_call_T<double>(method, self, nargs, args); + double result = 0.; + switch ((long)method) { + case 0: // static double staticAddToDouble(double) + assert(!self && nargs == 1); + result = ((CPPYY_G__value*)args)[0].obj.d + 0.01; + break; + case 12: // double addDataToDouble(double a) + assert(self && nargs == 1); + result = ((PseudoExample01*)self)->m_somedata + ((CPPYY_G__value*)args)[0].obj.d; + break; + default: + assert(!"method unknown in cppyy_call_d"); + break; + } + return result; } char* cppyy_call_s(cppyy_method_t method, cppyy_object_t self, int nargs, void* args) { @@ -149,10 +224,31 @@ return strout; } +cppyy_object_t cppyy_constructor(cppyy_method_t method, cppyy_type_t handle, int nargs, void* args) { + void* result = 0; + if (handle == s_handles["example01"]) { + switch ((long)method) { + case 10: + assert(nargs == 0); + result = new PseudoExample01; + break; + case 11: + assert(nargs == 1); + result = new PseudoExample01(((CPPYY_G__value*)args)[0].obj.in); + break; + default: + assert(!"method unknown in cppyy_constructor"); + break; + } + } + return (cppyy_object_t)result; +} + cppyy_methptrgetter_t cppyy_get_methptr_getter(cppyy_type_t /* handle */, cppyy_index_t /* method_index */) { return (cppyy_methptrgetter_t)0; } + /* handling of function argument buffer ----------------------------------- */ void* cppyy_allocate_function_args(size_t nargs) { CPPYY_G__value* args = (CPPYY_G__value*)malloc(nargs*sizeof(CPPYY_G__value)); @@ -200,7 +296,11 @@ } int cppyy_has_complex_hierarchy(cppyy_type_t /* handle */) { - return 1; + return 0; +} + +int cppyy_num_bases(cppyy_type_t /*handle*/) { + return 0; } @@ -252,11 +352,16 @@ /* method properties ----------------------------------------------------- */ -int cppyy_is_constructor(cppyy_type_t /* handle */, cppyy_index_t /* method_index */) { +int cppyy_is_constructor(cppyy_type_t handle, cppyy_index_t method_index) { + if (handle == s_handles["example01"]) + return example01_last_static_method <= method_index + && method_index < example01_last_constructor; return 0; } -int cppyy_is_staticmethod(cppyy_type_t /* handle */, cppyy_index_t /* method_index */) { +int cppyy_is_staticmethod(cppyy_type_t handle, cppyy_index_t method_index) { + if (handle == s_handles["example01"]) + return method_index < example01_last_static_method ? 1 : 0; return 1; } diff --git a/pypy/module/cppyy/test/conftest.py b/pypy/module/cppyy/test/conftest.py --- a/pypy/module/cppyy/test/conftest.py +++ b/pypy/module/cppyy/test/conftest.py @@ -7,11 +7,12 @@ if 'dummy' in lcapi.reflection_library: # run only tests that are covered by the dummy backend and tests # that do not rely on reflex - if not item.location[0] in ['test_helper.py', 'test_cppyy.py']: + if not ('test_helper.py' in item.location[0] or \ + 'test_cppyy.py' in item.location[0]): py.test.skip("genreflex is not installed") import re - if item.location[0] == 'test_cppyy.py' and \ - not re.search("test0[1-3]", item.location[2]): + if 'test_cppyy.py' in item.location[0] and \ + not re.search("test0[1-36]", item.location[2]): py.test.skip("genreflex is not installed") def pytest_configure(config): diff --git a/pypy/module/marshal/interp_marshal.py b/pypy/module/marshal/interp_marshal.py --- a/pypy/module/marshal/interp_marshal.py +++ b/pypy/module/marshal/interp_marshal.py @@ -330,21 +330,8 @@ def invalid_typecode(space, u, tc): - # %r not supported in rpython - #u.raise_exc('invalid typecode in unmarshal: %r' % tc) - c = ord(tc) - if c < 16: - s = '\\x0%x' % c - elif c < 32 or c > 126: - s = '\\x%x' % c - elif tc == '\\': - s = r'\\' - else: - s = tc - q = "'" - if s[0] == "'": - q = '"' - u.raise_exc('invalid typecode in unmarshal: ' + q + s + q) + u.raise_exc("bad marshal data (unknown type code)") + def register(codes, func): """NOT_RPYTHON""" diff --git a/pypy/module/marshal/test/test_marshal.py b/pypy/module/marshal/test/test_marshal.py --- a/pypy/module/marshal/test/test_marshal.py +++ b/pypy/module/marshal/test/test_marshal.py @@ -15,11 +15,14 @@ print(repr(s)) x = marshal.loads(s) assert x == case and type(x) is type(case) - f = BytesIO() - marshal.dump(case, f) - f.seek(0) - x = marshal.load(f) - assert x == case and type(x) is type(case) + + import sys + if '__pypy__' in sys.builtin_module_names: + f = StringIO.StringIO() + marshal.dump(case, f) + f.seek(0) + x = marshal.load(f) + assert x == case and type(x) is type(case) return x def test_None(self): @@ -190,8 +193,8 @@ def test_bad_typecode(self): import marshal - exc = raises(ValueError, marshal.loads, b'\x01') - assert r"'\x01'" in str(exc.value) + exc = raises(ValueError, marshal.loads, chr(1)) + assert str(exc.value) == "bad marshal data (unknown type code)" def test_bad_data(self): import marshal _______________________________________________ pypy-commit mailing list pypy-commit@python.org https://mail.python.org/mailman/listinfo/pypy-commit