[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