[pypy-commit] pypy reflex-support: groundwork for lazy lookup on namespaces (for now, only for updates)
wlav
noreply at buildbot.pypy.org
Tue Apr 3 01:43:36 CEST 2012
Author: Wim Lavrijsen <WLavrijsen at lbl.gov>
Branch: reflex-support
Changeset: r54159:228864642d3d
Date: 2012-03-30 13:51 -0700
http://bitbucket.org/pypy/pypy/changeset/228864642d3d/
Log: groundwork for lazy lookup on namespaces (for now, only for updates)
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
@@ -293,6 +293,12 @@
def c_method_signature(cppscope, method_index):
return charp2str_free(_c_method_signature(cppscope, method_index))
+c_method_index = rffi.llexternal(
+ "cppyy_method_index",
+ [C_SCOPE, rffi.CCHARP], rffi.INT,
+ threadsafe=threadsafe,
+ compilation_info=backend.eci)
+
c_get_method = rffi.llexternal(
"cppyy_get_method",
[C_SCOPE, rffi.INT], C_METHOD,
@@ -337,6 +343,12 @@
threadsafe=threadsafe,
compilation_info=backend.eci)
+c_data_member_index = rffi.llexternal(
+ "cppyy_data_member_index",
+ [C_SCOPE, rffi.CCHARP], rffi.INT,
+ threadsafe=threadsafe,
+ compilation_info=backend.eci)
+
# data member properties -----------------------------------------------------
c_is_publicdata = rffi.llexternal(
"cppyy_is_publicdata",
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
@@ -71,6 +71,8 @@
char* cppyy_method_arg_default(cppyy_scope_t scope, int method_index, int arg_index);
char* cppyy_method_signature(cppyy_scope_t scope, int method_index);
+ int cppyy_method_index(cppyy_scope_t scope, const char* name);
+
cppyy_method_t cppyy_get_method(cppyy_scope_t scope, int method_index);
/* method properties ----------------------------------------------------- */
@@ -83,6 +85,8 @@
char* cppyy_data_member_type(cppyy_scope_t scope, int data_member_index);
size_t cppyy_data_member_offset(cppyy_scope_t scope, int data_member_index);
+ int cppyy_data_member_index(cppyy_scope_t scope, const char* name);
+
/* data member properties ------------------------------------------------ */
int cppyy_is_publicdata(cppyy_type_t type, int data_member_index);
int cppyy_is_staticdata(cppyy_type_t type, int data_member_index);
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
@@ -413,7 +413,8 @@
try:
return self.methods[name]
except KeyError:
- raise self.missing_attribute_error(name)
+ pass
+ return self.find_overload(name)
def get_data_member_names(self):
return self.space.newlist([self.space.wrap(name) for name in self.data_members])
@@ -423,7 +424,8 @@
try:
return self.data_members[name]
except KeyError:
- raise self.missing_attribute_error(name)
+ pass
+ return self.find_data_member(name)
def missing_attribute_error(self, name):
return OperationError(
@@ -451,6 +453,13 @@
arg_defs.append((arg_type, arg_dflt))
return CPPFunction(self, method_index, result_type, arg_defs, args_required)
+ def _make_data_member(self, dm_name, dm_idx):
+ type_name = capi.c_data_member_type(self.handle, dm_idx)
+ offset = capi.c_data_member_offset(self.handle, dm_idx)
+ data_member = W_CPPDataMember(self.space, self.handle, type_name, offset, True)
+ self.data_members[dm_name] = data_member
+ return data_member
+
def _find_data_members(self):
num_data_members = capi.c_num_data_members(self.handle)
for i in range(num_data_members):
@@ -458,10 +467,24 @@
continue
data_member_name = capi.c_data_member_name(self.handle, i)
if not data_member_name in self.data_members:
- type_name = capi.c_data_member_type(self.handle, i)
- offset = capi.c_data_member_offset(self.handle, i)
- data_member = W_CPPDataMember(self.space, self.handle, type_name, offset, True)
- self.data_members[data_member_name] = data_member
+ self._make_data_member(data_member_name, i)
+
+ def find_overload(self, meth_name):
+ # TODO: collect all overloads, not just the non-overloaded version
+ meth_idx = capi.c_method_index(self.handle, meth_name)
+ if meth_idx < 0:
+ raise self.missing_attribute_error(meth_name)
+ cppfunction = self._make_cppfunction(meth_idx)
+ overload = W_CPPOverload(self.space, self.handle, meth_name, [cppfunction])
+ self.methods[meth_name] = overload
+ return overload
+
+ def find_data_member(self, dm_name):
+ dm_idx = capi.c_data_member_index(self.handle, dm_name)
+ if dm_idx < 0:
+ raise self.missing_attribute_error(dm_name)
+ data_member = self._make_data_member(dm_name, dm_idx)
+ return data_member
def update(self):
self._find_methods()
@@ -517,6 +540,12 @@
data_member = W_CPPDataMember(self.space, self.handle, type_name, offset, is_static)
self.data_members[data_member_name] = data_member
+ def find_overload(self, name):
+ raise self.missing_attribute_error(name)
+
+ def find_data_member(self, name):
+ raise self.missing_attribute_error(name)
+
def get_cppthis(self, cppinstance, scope_handle):
assert self.handle == cppinstance.cppclass.handle
return cppinstance.get_rawobject()
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
@@ -207,13 +207,6 @@
pycppitem = None
- # namespaces are "open"; TODO: classes are too (template methods, inner classes ...)
- if isinstance(scope, CppyyNamespaceMeta):
- global _loaded_dictionaries_isdirty
- if _loaded_dictionaries_isdirty: # TODO: this should be per namespace
- scope._cpp_proxy.update() # TODO: this is currently quadratic
- _loaded_dictionaries_isdirty = False
-
# classes
cppitem = cppyy._type_byname(true_name)
if cppitem:
@@ -365,15 +358,12 @@
pyclass.__getitem__ = pyclass.__setitem__
_loaded_dictionaries = {}
-_loaded_dictionaries_isdirty = True # should be per namespace
def load_reflection_info(name):
try:
return _loaded_dictionaries[name]
except KeyError:
dct = cppyy._load_dictionary(name)
_loaded_dictionaries[name] = dct
- global _loaded_dictionaries_isdirty
- _loaded_dictionaries_isdirty = True
return dct
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
@@ -372,6 +372,23 @@
return cppstring_to_cstring(sig.str());
}
+int cppyy_method_index(cppyy_scope_t handle, const char* name) {
+ Reflex::Scope s = scope_from_handle(handle);
+ // the following appears dumb, but the internal storage for Reflex is an
+ // unsorted std::vector anyway, so there's no gain to be had in using the
+ // Scope::FunctionMemberByName() function
+ int num_meth = s.FunctionMemberSize();
+ for (int imeth = 0; imeth < num_meth; ++imeth) {
+ Reflex::Member m = s.FunctionMemberAt(imeth);
+ if (m.Name() == name) {
+ if (m.IsPublic())
+ return imeth;
+ return -1;
+ }
+ }
+ return -1;
+}
+
cppyy_method_t cppyy_get_method(cppyy_scope_t handle, int method_index) {
Reflex::Scope s = scope_from_handle(handle);
Reflex::Member m = s.FunctionMemberAt(method_index);
@@ -436,6 +453,23 @@
return m.Offset();
}
+int cppyy_data_member_index(cppyy_scope_t handle, const char* name) {
+ Reflex::Scope s = scope_from_handle(handle);
+ // the following appears dumb, but the internal storage for Reflex is an
+ // unsorted std::vector anyway, so there's no gain to be had in using the
+ // Scope::DataMemberByName() function (which returns Member, not an index)
+ int num_dm = cppyy_num_data_members(handle);
+ for (int idm = 0; idm < num_dm; ++idm) {
+ Reflex::Member m = s.DataMemberAt(idm);
+ if (m.Name() == name || m.Name(Reflex::FINAL) == name) {
+ if (m.IsPublic())
+ return idm;
+ return -1;
+ }
+ }
+ return -1;
+}
+
/* data member properties ------------------------------------------------ */
int cppyy_is_publicdata(cppyy_scope_t handle, int data_member_index) {
diff --git a/pypy/module/cppyy/test/Makefile b/pypy/module/cppyy/test/Makefile
--- a/pypy/module/cppyy/test/Makefile
+++ b/pypy/module/cppyy/test/Makefile
@@ -1,5 +1,6 @@
-dicts = example01Dict.so datatypesDict.so advancedcppDict.so overloadsDict.so \
-stltypesDict.so operatorsDict.so fragileDict.so std_streamsDict.so
+dicts = example01Dict.so datatypesDict.so advancedcppDict.so advancedcpp2Dict.so \
+overloadsDict.so stltypesDict.so operatorsDict.so fragileDict.so \
+std_streamsDict.so
all : $(dicts)
ROOTSYS := ${ROOTSYS}
diff --git a/pypy/module/cppyy/test/advancedcpp.cxx b/pypy/module/cppyy/test/advancedcpp.cxx
--- a/pypy/module/cppyy/test/advancedcpp.cxx
+++ b/pypy/module/cppyy/test/advancedcpp.cxx
@@ -24,6 +24,9 @@
int a_ns::d_ns::e_class::s_e = 55;
int a_ns::d_ns::e_class::f_class::s_f = 66;
+int a_ns::get_g_a() { return g_a; }
+int a_ns::d_ns::get_g_d() { return g_d; }
+
// for template testing
template class T1<int>;
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
@@ -100,6 +100,7 @@
//===========================================================================
namespace a_ns { // for namespace testing
extern int g_a;
+ int get_g_a();
struct b_class {
b_class() { m_b = -2; }
@@ -115,6 +116,7 @@
namespace d_ns {
extern int g_d;
+ int get_g_d();
struct e_class {
e_class() { m_e = -5; }
diff --git a/pypy/module/cppyy/test/advancedcpp.xml b/pypy/module/cppyy/test/advancedcpp.xml
--- a/pypy/module/cppyy/test/advancedcpp.xml
+++ b/pypy/module/cppyy/test/advancedcpp.xml
@@ -22,7 +22,9 @@
<namespace pattern="a_ns::*" />
<class pattern="a_ns::*" />
<variable name="a_ns::g_a" />
+ <function name="a_ns::get_g_a" />
<variable name="a_ns::d_ns::g_d" />
+ <function name="a_ns::d_ns::get_g_d" />
<class name="some_abstract_class" />
<class name="some_concrete_class" />
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
@@ -10,9 +10,10 @@
def setup_module(mod):
if sys.platform == 'win32':
py.test.skip("win32 not supported so far")
- err = os.system("cd '%s' && make advancedcppDict.so" % currpath)
- if err:
- raise OSError("'make' failed (see stderr)")
+ for refl_dict in ["advancedcppDict.so", "advancedcpp2Dict.so"]:
+ err = os.system("cd '%s' && make %s" % (currpath, refl_dict))
+ if err:
+ raise OSError("'make' failed (see stderr)")
class AppTestADVANCEDCPP:
def setup_class(cls):
@@ -113,23 +114,55 @@
import cppyy
gbl = cppyy.gbl
+ assert gbl.a_ns is gbl.a_ns
+ assert gbl.a_ns.d_ns is gbl.a_ns.d_ns
+
+ assert gbl.a_ns.b_class is gbl.a_ns.b_class
+ assert gbl.a_ns.b_class.c_class is gbl.a_ns.b_class.c_class
+ assert gbl.a_ns.d_ns.e_class is gbl.a_ns.d_ns.e_class
+ assert gbl.a_ns.d_ns.e_class.f_class is gbl.a_ns.d_ns.e_class.f_class
+
assert gbl.a_ns.g_a == 11
+ assert gbl.a_ns.get_g_a() == 11
assert gbl.a_ns.b_class.s_b == 22
assert gbl.a_ns.b_class().m_b == -2
assert gbl.a_ns.b_class.c_class.s_c == 33
assert gbl.a_ns.b_class.c_class().m_c == -3
assert gbl.a_ns.d_ns.g_d == 44
+ assert gbl.a_ns.d_ns.get_g_d() == 44
assert gbl.a_ns.d_ns.e_class.s_e == 55
assert gbl.a_ns.d_ns.e_class().m_e == -5
assert gbl.a_ns.d_ns.e_class.f_class.s_f == 66
assert gbl.a_ns.d_ns.e_class.f_class().m_f == -6
+ def test03a_namespace_lookup_on_update(self):
+ """Test whether namespaces can be shared across dictionaries."""
+
+ import cppyy
+ gbl = cppyy.gbl
+
+ lib2 = cppyy.load_reflection_info("advancedcpp2Dict.so")
+
assert gbl.a_ns is gbl.a_ns
assert gbl.a_ns.d_ns is gbl.a_ns.d_ns
- assert gbl.a_ns.b_class is gbl.a_ns.b_class
- assert gbl.a_ns.d_ns.e_class is gbl.a_ns.d_ns.e_class
- assert gbl.a_ns.d_ns.e_class.f_class is gbl.a_ns.d_ns.e_class.f_class
+ assert gbl.a_ns.g_class is gbl.a_ns.g_class
+ assert gbl.a_ns.g_class.h_class is gbl.a_ns.g_class.h_class
+ assert gbl.a_ns.d_ns.i_class is gbl.a_ns.d_ns.i_class
+ assert gbl.a_ns.d_ns.i_class.j_class is gbl.a_ns.d_ns.i_class.j_class
+
+ assert gbl.a_ns.g_g == 77
+ assert gbl.a_ns.get_g_g() == 77
+ assert gbl.a_ns.g_class.s_g == 88
+ assert gbl.a_ns.g_class().m_g == -7
+ assert gbl.a_ns.g_class.h_class.s_h == 99
+ assert gbl.a_ns.g_class.h_class().m_h == -8
+ assert gbl.a_ns.d_ns.g_i == 111
+ assert gbl.a_ns.d_ns.get_g_i() == 111
+ assert gbl.a_ns.d_ns.i_class.s_i == 222
+ assert gbl.a_ns.d_ns.i_class().m_i == -9
+ assert gbl.a_ns.d_ns.i_class.j_class.s_j == 333
+ assert gbl.a_ns.d_ns.i_class.j_class().m_j == -10
def test04_template_types(self):
"""Test bindings of templated types"""
diff --git a/pypy/module/cppyy/test/test_pythonify.py b/pypy/module/cppyy/test/test_pythonify.py
--- a/pypy/module/cppyy/test/test_pythonify.py
+++ b/pypy/module/cppyy/test/test_pythonify.py
@@ -24,7 +24,7 @@
import cppyy
return cppyy.load_reflection_info(%r)""" % (test_dct, ))
- def test01_load_dicionary_cache(self):
+ def test01_load_dictionary_cache(self):
"""Test whether loading a dictionary twice results in the same object."""
import cppyy
lib2 = cppyy.load_reflection_info(self.test_dct)
More information about the pypy-commit
mailing list