Commits

wlav committed 8812443

o) first attempt at getting __setitem__ right
o) more doc/comment strings

Comments (0)

Files changed (3)

pypy/module/cppyy/executor.py

         result = libffifunc.call(argchain, rffi.INTP)
         return space.wrap(result[0])
 
+class IntRefExecutor(FunctionExecutor):
+    _immutable_ = True
+    libffitype = libffi.types.pointer
+
+    def __init__(self, space, extra):
+        FunctionExecutor.__init__(self, space, extra)
+        self.do_assign = False
+        self.item = rffi.cast(rffi.INT, 0)
+
+    def set_item(self, space, w_item):
+        self.item = rffi.cast(rffi.INT, space.c_int_w(w_item))
+        self.do_assign = True
+
+    def _wrap_result(self, space, intptr):
+        if self.do_assign:
+            intptr[0] = self.item
+        return space.wrap(intptr[0])    # all paths, for rtyper
+
+    def execute(self, space, cppmethod, cppthis, num_args, args):
+        result = rffi.cast(rffi.INTP, capi.c_call_r(cppmethod, cppthis, num_args, args))
+        return self._wrap_result(space, result)
+
+    def execute_libffi(self, space, libffifunc, argchain):
+        result = libffifunc.call(argchain, rffi.INTP)
+        return self._wrap_result(space, result)
+
 class ConstLongRefExecutor(ConstIntRefExecutor):
     _immutable_ = True
     libffitype = libffi.types.pointer
 _executors["unsigned short"]      = ShortExecutor
 _executors["int"]                 = IntExecutor
 _executors["const int&"]          = ConstIntRefExecutor
-_executors["int&"]                = ConstIntRefExecutor
+_executors["int&"]                = IntRefExecutor
 _executors["unsigned"]            = UnsignedIntExecutor
 _executors["long"]                = LongExecutor
 _executors["unsigned long"]       = UnsignedLongExecutor

pypy/module/cppyy/interp_cppyy.py

 
 
 class CPPMethod(object):
-    """ A concrete function after overloading has been resolved """
+    """Dispatcher of methods. Checks the arguments, find the corresponding FFI
+    function if available, makes the call, and returns the wrapped result. It
+    also takes care of offset casting and recycling of known objects through
+    the memory_regulator."""
     _immutable_ = True
     
     def __init__(self, space, containing_scope, method_index, arg_defs, args_required):
 
 
 class CPPFunction(CPPMethod):
+    """Global (namespaced) function dispatcher. For now, the base class has
+    all the needed functionality, by allowing the C++ this pointer to be null
+    in the call. An optimization is expected there, however."""
     _immutable_ = True
 
     def __repr__(self):
 
 
 class CPPConstructor(CPPMethod):
+    """Method dispatcher that constructs new objects. In addition to the call,
+    it allocates memory for the newly constructed object and sets ownership
+    to Python."""
     _immutable_ = True
 
     def call(self, cppthis, args_w):
         return "CPPConstructor: %s" % self.signature()
 
 
+class CPPSetItem(CPPMethod):
+    """Method dispatcher specific to Python's __setitem__ mapped onto C++'s
+    operator[](int). The former function takes an extra argument to assign to
+    the return type of the latter."""
+    _immutable_ = True
+
+    def call(self, cppthis, args_w):
+        end = len(args_w)-1
+        if 0 <= end:
+            w_item = args_w[end]
+            args_w = args_w[:end]
+            if self.converters is None:
+                self._setup(cppthis)
+            self.executor.set_item(self.space, w_item) # TODO: what about threads?
+        CPPMethod.call(self, cppthis, args_w)
+
+
 class W_CPPOverload(Wrappable):
+    """Dispatcher that is actually available at the app-level: it is a
+    collection of (possibly) overloaded methods or functions. It calls these
+    in order and deals with error handling and reporting."""
     _immutable_ = True
 
     def __init__(self, space, containing_scope, functions):
                 capi.c_method_name(self, idx),
                 capi.c_method_num_args(self, idx),
                 capi.c_method_result_type(self, idx))
-            cppmethod = self._make_cppfunction(idx)
+            cppmethod = self._make_cppfunction(pyname, idx)
             methods_temp.setdefault(pyname, []).append(cppmethod)
         for pyname, methods in methods_temp.iteritems():
             overload = W_CPPOverload(self.space, self, methods[:])
     _immutable_ = True
     kind = "namespace"
 
-    def _make_cppfunction(self, index):
+    def _make_cppfunction(self, pyname, index):
         num_args = capi.c_method_num_args(self, index)
         args_required = capi.c_method_req_args(self, index)
         arg_defs = []
         meth_idx = capi.c_method_index_from_name(self, meth_name)
         if meth_idx == -1:
             raise self.missing_attribute_error(meth_name)
-        cppfunction = self._make_cppfunction(meth_idx)
+        cppfunction = self._make_cppfunction(meth_name, meth_idx)
         overload = W_CPPOverload(self.space, self, [cppfunction])
         return overload
 
     _immutable_ = True
     kind = "class"
 
-    def _make_cppfunction(self, index):
+    def _make_cppfunction(self, pyname, index):
         num_args = capi.c_method_num_args(self, index)
         args_required = capi.c_method_req_args(self, index)
         arg_defs = []
             cls = CPPConstructor
         elif capi.c_is_staticmethod(self, index):
             cls = CPPFunction
+        elif pyname == "__setitem__":
+            cls = CPPSetItem
         else:
             cls = CPPMethod
         return cls(self.space, self, index, arg_defs, args_required)
         meth_idx = capi.c_get_global_operator(self.cppclass, other.cppclass, "==")
         if meth_idx != -1:
             gbl = scope_byname(self.space, "")
-            f = gbl._make_cppfunction(meth_idx)
+            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])

pypy/module/cppyy/test/test_stltypes.py

 
         #-----
         for i in range(self.N):
-          #  v[i] = i
-          #  assert v[i] == i
-          #  assert v.at(i) == i
+            v[i] = i
+            assert v[i] == i
+            assert v.at(i) == i
             pass
 
         assert v.size() == self.N