[pypy-commit] pypy reflex-support: improve pythonizations and use of std::vector and std::list
wlav
noreply at buildbot.pypy.org
Fri Jul 20 09:15:11 CEST 2012
Author: Wim Lavrijsen <WLavrijsen at lbl.gov>
Branch: reflex-support
Changeset: r56245:a10072d752f3
Date: 2012-07-19 23:48 -0700
http://bitbucket.org/pypy/pypy/changeset/a10072d752f3/
Log: improve pythonizations and use of std::vector and std::list
diff --git a/pypy/module/cppyy/capi/__init__.py b/pypy/module/cppyy/capi/__init__.py
--- a/pypy/module/cppyy/capi/__init__.py
+++ b/pypy/module/cppyy/capi/__init__.py
@@ -360,11 +360,13 @@
return _c_get_method(cppscope.handle, index)
_c_get_global_operator = rffi.llexternal(
"cppyy_get_global_operator",
- [C_SCOPE, C_SCOPE, rffi.CCHARP], WLAVC_INDEX,
+ [C_SCOPE, C_SCOPE, C_SCOPE, rffi.CCHARP], WLAVC_INDEX,
threadsafe=ts_reflect,
compilation_info=backend.eci)
-def c_get_global_operator(lc, rc, op):
- return _c_get_global_operator(lc.handle, rc.handle, op)
+def c_get_global_operator(nss, lc, rc, op):
+ if nss is not None:
+ return _c_get_global_operator(nss.handle, lc.handle, rc.handle, op)
+ return rffi.cast(WLAVC_INDEX, -1)
# method properties ----------------------------------------------------------
_c_is_constructor = rffi.llexternal(
diff --git a/pypy/module/cppyy/include/capi.h b/pypy/module/cppyy/include/capi.h
--- a/pypy/module/cppyy/include/capi.h
+++ b/pypy/module/cppyy/include/capi.h
@@ -82,7 +82,8 @@
char* cppyy_method_signature(cppyy_scope_t scope, cppyy_index_t idx);
cppyy_method_t cppyy_get_method(cppyy_scope_t scope, cppyy_index_t idx);
- cppyy_index_t cppyy_get_global_operator(cppyy_scope_t lc, cppyy_scope_t rc, const char* op);
+ cppyy_index_t cppyy_get_global_operator(
+ cppyy_scope_t scope, cppyy_scope_t lc, cppyy_scope_t rc, const char* op);
/* method properties ----------------------------------------------------- */
int cppyy_is_constructor(cppyy_type_t type, cppyy_index_t idx);
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
@@ -781,14 +781,17 @@
def instance__eq__(self, w_other):
other = self.space.interp_w(W_CPPInstance, w_other, can_be_None=False)
- # get here if no class-specific overloaded operator is available
- meth_idx = capi.c_get_global_operator(self.cppclass, other.cppclass, "==")
- if meth_idx != -1:
- gbl = scope_byname(self.space, "")
- f = gbl._make_cppfunction("operator==", meth_idx)
- ol = W_CPPOverload(self.space, scope_byname(self.space, ""), [f])
- # TODO: cache this operator (currently cached by JIT in capi/__init__.py)
- return ol.call(self, [self, w_other])
+ # get here if no class-specific overloaded operator is available, try to
+ # find a global overload in gbl, in __gnu_cxx (for iterators), or in the
+ # scopes of the argument classes (TODO: implement that last)
+ for name in ["", "__gnu_cxx"]:
+ nss = scope_byname(self.space, name)
+ meth_idx = capi.c_get_global_operator(nss, self.cppclass, other.cppclass, "==")
+ if meth_idx != -1:
+ f = nss._make_cppfunction("operator==", meth_idx)
+ ol = W_CPPOverload(self.space, nss, [f])
+ # TODO: cache this operator
+ return ol.call(self, [self, w_other])
# fallback: direct pointer comparison (the class comparison is needed since the
# first data member in a struct and the struct have the same address)
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
@@ -323,19 +323,10 @@
return self
pyclass.__iadd__ = __iadd__
- # for STL iterators, whose comparison functions live globally for gcc
- # TODO: this needs to be solved fundamentally for all classes
- if 'iterator' in pyclass.__name__:
- if hasattr(gbl, '__gnu_cxx'):
- if hasattr(gbl.__gnu_cxx, '__eq__'):
- setattr(pyclass, '__eq__', gbl.__gnu_cxx.__eq__)
- if hasattr(gbl.__gnu_cxx, '__ne__'):
- setattr(pyclass, '__ne__', gbl.__gnu_cxx.__ne__)
-
- # map begin()/end() protocol to iter protocol
- # TODO: the vector hack is there b/c it's safer/faster to use the normal
- # index iterator (with len checking) rather than the begin()/end() iterators
- if not 'vector' in pyclass.__name__ and \
+ # map begin()/end() protocol to iter protocol on STL(-like) classes, but
+ # not on vector, for which otherwise the user has to make sure that the
+ # global == and != for its iterators are reflected, which is a hassle ...
+ if not 'vector' in pyclass.__name__[:11] and \
(hasattr(pyclass, 'begin') and hasattr(pyclass, 'end')):
# TODO: check return type of begin() and end() for existence
def __iter__(self):
diff --git a/pypy/module/cppyy/src/cintcwrapper.cxx b/pypy/module/cppyy/src/cintcwrapper.cxx
--- a/pypy/module/cppyy/src/cintcwrapper.cxx
+++ b/pypy/module/cppyy/src/cintcwrapper.cxx
@@ -264,6 +264,12 @@
// actual typedef resolution; add back array declartion portion, if needed
std::string rt = ti.TrueName();
+
+ // builtin STL types have fake typedefs :/
+ G__TypeInfo ti_test(rt.c_str());
+ if (!ti_test.IsValid())
+ return cppstring_to_cstring(cppitem_name);
+
if (pos != std::string::npos)
rt += tname.substr(pos, std::string::npos);
return cppstring_to_cstring(rt);
@@ -712,15 +718,14 @@
return method;
}
-cppyy_index_t cppyy_get_global_operator(cppyy_scope_t lc, cppyy_scope_t rc, const char* op) {
+cppyy_index_t cppyy_get_global_operator(cppyy_scope_t scope, cppyy_scope_t lc, cppyy_scope_t rc, const char* op) {
TClassRef lccr = type_from_handle(lc);
- if (!lccr.GetClass())
+ TClassRef rccr = type_from_handle(rc);
+
+ if (!lccr.GetClass() || !rccr.GetClass() || scope != GLOBAL_HANDLE)
return (cppyy_index_t)-1; // (void*)-1 is in kernel space, so invalid as a method handle
+
std::string lcname = lccr->GetName();
-
- TClassRef rccr = type_from_handle(lc);
- if (!rccr.GetClass())
- return (cppyy_index_t)-1;
std::string rcname = rccr->GetName();
std::string opname = "operator";
diff --git a/pypy/module/cppyy/src/reflexcwrapper.cxx b/pypy/module/cppyy/src/reflexcwrapper.cxx
--- a/pypy/module/cppyy/src/reflexcwrapper.cxx
+++ b/pypy/module/cppyy/src/reflexcwrapper.cxx
@@ -437,8 +437,35 @@
return (cppyy_method_t)m.Stubfunction();
}
-cppyy_index_t cppyy_get_global_operator(cppyy_scope_t lc, cppyy_scope_t rc, const char* op) {
- return (cppyy_index_t)-1; /* not needed yet; covered in pythonify.py */
+cppyy_method_t cppyy_get_global_operator(cppyy_scope_t scope, cppyy_scope_t lc, cppyy_scope_t rc, const char* op) {
+ Reflex::Type lct = type_from_handle(lc);
+ Reflex::Type rct = type_from_handle(rc);
+ Reflex::Scope nss = scope_from_handle(scope);
+
+ if (!lct || !rct || !nss)
+ return (cppyy_index_t)-1; // (void*)-1 is in kernel space, so invalid as a method handle
+
+ std::string lcname = lct.Name(Reflex::SCOPED|Reflex::FINAL);
+ std::string rcname = rct.Name(Reflex::SCOPED|Reflex::FINAL);
+
+ std::string opname = "operator";
+ opname += op;
+
+ for (int idx = 0; idx < (int)nss.FunctionMemberSize(); ++idx) {
+ Reflex::Member m = nss.FunctionMemberAt(idx);
+ if (m.FunctionParameterSize() != 2)
+ continue;
+
+ if (m.Name() == opname) {
+ Reflex::Type mt = m.TypeOf();
+ if (lcname == mt.FunctionParameterAt(0).Name(Reflex::SCOPED|Reflex::FINAL) &&
+ rcname == mt.FunctionParameterAt(1).Name(Reflex::SCOPED|Reflex::FINAL)) {
+ return (cppyy_index_t)idx;
+ }
+ }
+ }
+
+ return (cppyy_index_t)-1;
}
diff --git a/pypy/module/cppyy/test/std_streams_LinkDef.h b/pypy/module/cppyy/test/std_streams_LinkDef.h
--- a/pypy/module/cppyy/test/std_streams_LinkDef.h
+++ b/pypy/module/cppyy/test/std_streams_LinkDef.h
@@ -4,6 +4,4 @@
#pragma link off all classes;
#pragma link off all functions;
-#pragma link C++ class std::ostream;
-
#endif
diff --git a/pypy/module/cppyy/test/stltypes.cxx b/pypy/module/cppyy/test/stltypes.cxx
--- a/pypy/module/cppyy/test/stltypes.cxx
+++ b/pypy/module/cppyy/test/stltypes.cxx
@@ -1,9 +1,6 @@
#include "stltypes.h"
-#define STLTYPES_EXPLICIT_INSTANTIATION(STLTYPE, TTYPE) \
-template class std::STLTYPE< TTYPE >; \
-template class __gnu_cxx::__normal_iterator<TTYPE*, std::STLTYPE< TTYPE > >; \
-template class __gnu_cxx::__normal_iterator<const TTYPE*, std::STLTYPE< TTYPE > >;\
+#define STLTYPES_EXPLICIT_INSTANTIATION_WITH_COMPS(STLTYPE, TTYPE) \
namespace __gnu_cxx { \
template bool operator==(const std::STLTYPE< TTYPE >::iterator&, \
const std::STLTYPE< TTYPE >::iterator&); \
@@ -11,12 +8,8 @@
const std::STLTYPE< TTYPE >::iterator&); \
}
-
-//- explicit instantiations of used types
-STLTYPES_EXPLICIT_INSTANTIATION(vector, int)
-STLTYPES_EXPLICIT_INSTANTIATION(vector, float)
-STLTYPES_EXPLICIT_INSTANTIATION(vector, double)
-STLTYPES_EXPLICIT_INSTANTIATION(vector, just_a_class)
+//- explicit instantiations of used comparisons
+STLTYPES_EXPLICIT_INSTANTIATION_WITH_COMPS(vector, int)
//- class with lots of std::string handling
stringy_class::stringy_class(const char* s) : m_string(s) {}
diff --git a/pypy/module/cppyy/test/stltypes.h b/pypy/module/cppyy/test/stltypes.h
--- a/pypy/module/cppyy/test/stltypes.h
+++ b/pypy/module/cppyy/test/stltypes.h
@@ -3,32 +3,50 @@
#include <string>
#include <vector>
-#define STLTYPES_EXPLICIT_INSTANTIATION_DECL(STLTYPE, TTYPE) \
-extern template class std::STLTYPE< TTYPE >; \
-extern template class __gnu_cxx::__normal_iterator<TTYPE*, std::STLTYPE< TTYPE > >;\
-extern template class __gnu_cxx::__normal_iterator<const TTYPE*, std::STLTYPE< TTYPE > >;\
-namespace __gnu_cxx { \
-extern template bool operator==(const std::STLTYPE< TTYPE >::iterator&, \
- const std::STLTYPE< TTYPE >::iterator&); \
-extern template bool operator!=(const std::STLTYPE< TTYPE >::iterator&, \
- const std::STLTYPE< TTYPE >::iterator&); \
-}
-
-
//- basic example class
class just_a_class {
public:
int m_i;
};
+#define STLTYPE_INSTANTIATION(STLTYPE, TTYPE, N) \
+ std::STLTYPE<TTYPE > STLTYPE##_##N; \
+ std::STLTYPE<TTYPE >::iterator STLTYPE##_##N##_i; \
+ std::STLTYPE<TTYPE >::const_iterator STLTYPE##_##N##_ci
-#ifndef __CINT__
-//- explicit instantiations of used types
-STLTYPES_EXPLICIT_INSTANTIATION_DECL(vector, int)
-STLTYPES_EXPLICIT_INSTANTIATION_DECL(vector, float)
-STLTYPES_EXPLICIT_INSTANTIATION_DECL(vector, double)
-STLTYPES_EXPLICIT_INSTANTIATION_DECL(vector, just_a_class)
-#endif
+//- instantiations of used STL types
+namespace {
+
+ struct _CppyyVectorInstances {
+
+ STLTYPE_INSTANTIATION(vector, int, 1);
+ STLTYPE_INSTANTIATION(vector, float, 2);
+ STLTYPE_INSTANTIATION(vector, double, 3);
+ STLTYPE_INSTANTIATION(vector, just_a_class, 4);
+
+ };
+
+ struct _CppyyListInstances {
+
+ STLTYPE_INSTANTIATION(list, int, 1);
+ STLTYPE_INSTANTIATION(list, float, 2);
+ STLTYPE_INSTANTIATION(list, double, 3);
+
+ };
+
+} // unnamed namespace
+
+#define STLTYPES_EXPLICIT_INSTANTIATION_DECL_COMPS(STLTYPE, TTYPE) \
+namespace __gnu_cxx { \
+extern template bool operator==(const std::STLTYPE< TTYPE >::iterator&, \
+ const std::STLTYPE< TTYPE >::iterator&); \
+extern template bool operator!=(const std::STLTYPE< TTYPE >::iterator&, \
+ const std::STLTYPE< TTYPE >::iterator&); \
+}
+
+// comps for int only to allow testing: normal use of vector is looping over a
+// range-checked version of __getitem__
+STLTYPES_EXPLICIT_INSTANTIATION_DECL_COMPS(vector, int)
//- class with lots of std::string handling
diff --git a/pypy/module/cppyy/test/stltypes.xml b/pypy/module/cppyy/test/stltypes.xml
--- a/pypy/module/cppyy/test/stltypes.xml
+++ b/pypy/module/cppyy/test/stltypes.xml
@@ -3,12 +3,18 @@
<namespace name="std" />
<class pattern="std::vector<*>" />
- <class pattern="__gnu_cxx::__normal_iterator<*>" />
- <class pattern="__gnu_cxx::new_allocator<*>" />
<class pattern="std::_Vector_base<*>" />
<class pattern="std::_Vector_base<*>::_Vector_impl" />
- <class pattern="std::allocator<*>" />
+ <class pattern="std::vector<*>::iterator" />
+ <class pattern="std::vector<*>::const_iterator" />
+ <class pattern="std::list<*>" />
+ <class pattern="std::_List_base<*>" />
+ <class pattern="std::list<*>::iterator" />
+ <class pattern="std::list<*>::const_iterator" />
+ <class name="std::__detail::_List_node_base" />
+
+ <class pattern="__gnu_cxx::__normal_iterator<*>" />
<function name="__gnu_cxx::operator=="/>
<function name="__gnu_cxx::operator!="/>
diff --git a/pypy/module/cppyy/test/test_stltypes.py b/pypy/module/cppyy/test/test_stltypes.py
--- a/pypy/module/cppyy/test/test_stltypes.py
+++ b/pypy/module/cppyy/test/test_stltypes.py
@@ -17,7 +17,6 @@
class AppTestSTLVECTOR:
def setup_class(cls):
cls.space = space
- env = os.environ
cls.w_N = space.wrap(13)
cls.w_test_dct = space.wrap(test_dct)
cls.w_stlvector = cls.space.appexec([], """():
@@ -46,13 +45,14 @@
assert tv1 is tv2
assert tv1.iterator is cppyy.gbl.std.vector(p_type).iterator
- #-----
+ #-----
v = tv1(); v += range(self.N) # default args from Reflex are useless :/
- assert v.begin().__eq__(v.begin())
- assert v.begin() == v.begin()
- assert v.end() == v.end()
- assert v.begin() != v.end()
- assert v.end() != v.begin()
+ if p_type == int: # only type with == and != reflected in .xml
+ assert v.begin().__eq__(v.begin())
+ assert v.begin() == v.begin()
+ assert v.end() == v.end()
+ assert v.begin() != v.end()
+ assert v.end() != v.begin()
#-----
for i in range(self.N):
@@ -204,7 +204,6 @@
class AppTestSTLSTRING:
def setup_class(cls):
cls.space = space
- env = os.environ
cls.w_test_dct = space.wrap(test_dct)
cls.w_stlstring = cls.space.appexec([], """():
import cppyy
@@ -279,3 +278,59 @@
c.set_string1(s)
assert t0 == c.get_string1()
assert s == c.get_string1()
+
+
+class AppTestSTLSTRING:
+ def setup_class(cls):
+ cls.space = space
+ cls.w_N = space.wrap(13)
+ cls.w_test_dct = space.wrap(test_dct)
+ cls.w_stlstring = cls.space.appexec([], """():
+ import cppyy
+ return cppyy.load_reflection_info(%r)""" % (test_dct, ))
+
+ def test01_builtin_list_type(self):
+ """Test access to a list<int>"""
+
+ import cppyy
+ from cppyy.gbl import std
+
+ type_info = (
+ ("int", int),
+ ("float", "float"),
+ ("double", "double"),
+ )
+
+ for c_type, p_type in type_info:
+ tl1 = getattr(std, 'list<%s>' % c_type)
+ tl2 = cppyy.gbl.std.list(p_type)
+ assert tl1 is tl2
+ assert tl1.iterator is cppyy.gbl.std.list(p_type).iterator
+
+ #-----
+ a = tl1()
+ for i in range(self.N):
+ a.push_back( i )
+
+ assert len(a) == self.N
+ assert 11 < self.N
+ assert 11 in a
+
+ #-----
+ ll = list(a)
+ for i in range(self.N):
+ assert ll[i] == i
+
+ for val in a:
+ assert ll[ll.index(val)] == val
+
+ def test02_empty_list_type(self):
+ """Test behavior of empty list<int>"""
+
+ import cppyy
+ from cppyy.gbl import std
+
+ a = std.list(int)()
+ for arg in a:
+ pass
+
More information about the pypy-commit
mailing list