[pypy-commit] pypy reflex-support: refactoring all duplicated codes from converter.py and executor.py

wlav noreply at buildbot.pypy.org
Wed Jul 11 09:28:22 CEST 2012


Author: Wim Lavrijsen <WLavrijsen at lbl.gov>
Branch: reflex-support
Changeset: r56022:9948a2bd6028
Date: 2012-07-11 00:28 -0700
http://bitbucket.org/pypy/pypy/changeset/9948a2bd6028/

Log:	refactoring all duplicated codes from converter.py and executor.py

diff --git a/pypy/module/cppyy/converter.py b/pypy/module/cppyy/converter.py
--- a/pypy/module/cppyy/converter.py
+++ b/pypy/module/cppyy/converter.py
@@ -4,12 +4,12 @@
 
 from pypy.rpython.lltypesystem import rffi, lltype
 from pypy.rlib.rarithmetic import r_singlefloat
-from pypy.rlib import jit, libffi, clibffi, rfloat
+from pypy.rlib import libffi, clibffi, rfloat
 
 from pypy.module._rawffi.interp_rawffi import unpack_simple_shape
 from pypy.module._rawffi.array import W_Array
 
-from pypy.module.cppyy import helper, capi
+from pypy.module.cppyy import helper, capi, ffitypes
 
 # Converter objects are used to translate between RPython and C++. They are
 # defined by the type name for which they provide conversion. Uses are for
@@ -276,26 +276,8 @@
         else:
             address[0] = '\x00'
 
-class CharConverter(TypeConverter):
+class CharConverter(ffitypes.typeid(rffi.CHAR), TypeConverter):
     _immutable_ = True
-    libffitype = libffi.types.schar
-
-    def _unwrap_object(self, space, w_value):
-        # allow int to pass to char and make sure that str is of length 1
-        if space.isinstance_w(w_value, space.w_int):
-            ival = space.c_int_w(w_value)
-            if ival < 0 or 256 <= ival:
-                raise OperationError(space.w_ValueError,
-                                     space.wrap("char arg not in range(256)"))
-
-            value = rffi.cast(rffi.CHAR, space.c_int_w(w_value))
-        else:
-            value = space.str_w(w_value)
-
-        if len(value) != 1:  
-            raise OperationError(space.w_ValueError,
-                                 space.wrap("char expected, got string of size %d" % len(value)))
-        return value[0] # turn it into a "char" to the annotator
 
     def convert_argument(self, space, w_obj, address, call_local):
         x = rffi.cast(rffi.CCHARP, address)
@@ -312,132 +294,8 @@
         address = rffi.cast(rffi.CCHARP, self._get_raw_address(space, w_obj, offset))
         address[0] = self._unwrap_object(space, w_value)
 
-
-class ShortConverter(IntTypeConverterMixin, TypeConverter):
+class FloatConverter(ffitypes.typeid(rffi.FLOAT), FloatTypeConverterMixin, TypeConverter):
     _immutable_ = True
-    libffitype = libffi.types.sshort
-    c_type     = rffi.SHORT
-    c_ptrtype  = rffi.SHORTP
-
-    def __init__(self, space, default):
-        self.default = rffi.cast(rffi.SHORT, capi.c_strtoll(default))
-
-    def _unwrap_object(self, space, w_obj):
-        return rffi.cast(rffi.SHORT, space.int_w(w_obj))
-
-class UnsignedShortConverter(IntTypeConverterMixin, TypeConverter):
-    _immutable_ = True
-    libffitype = libffi.types.sshort
-    c_type     = rffi.USHORT
-    c_ptrtype  = rffi.USHORTP
-
-    def __init__(self, space, default):
-        self.default = rffi.cast(self.c_type, capi.c_strtoull(default))
-
-    def _unwrap_object(self, space, w_obj):
-        return rffi.cast(self.c_type, space.int_w(w_obj))
-
-class IntConverter(IntTypeConverterMixin, TypeConverter):
-    _immutable_ = True
-    libffitype = libffi.types.sint
-    c_type     = rffi.INT
-    c_ptrtype  = rffi.INTP
-
-    def __init__(self, space, default):
-        self.default = rffi.cast(self.c_type, capi.c_strtoll(default))
-
-    def _unwrap_object(self, space, w_obj):
-        return rffi.cast(self.c_type, space.c_int_w(w_obj))
-
-class UnsignedIntConverter(IntTypeConverterMixin, TypeConverter):
-    _immutable_ = True
-    libffitype = libffi.types.uint
-    c_type     = rffi.UINT
-    c_ptrtype  = rffi.UINTP
-
-    def __init__(self, space, default):
-        self.default = rffi.cast(self.c_type, capi.c_strtoull(default))
-
-    def _unwrap_object(self, space, w_obj):
-        return rffi.cast(self.c_type, space.uint_w(w_obj))
-
-class LongConverter(IntTypeConverterMixin, TypeConverter):
-    _immutable_ = True
-    libffitype = libffi.types.slong
-    c_type     = rffi.LONG
-    c_ptrtype  = rffi.LONGP
-
-    def __init__(self, space, default):
-        self.default = rffi.cast(self.c_type, capi.c_strtoll(default))
-
-    def _unwrap_object(self, space, w_obj):
-        return space.int_w(w_obj)
-
-class ConstLongRefConverter(ConstRefNumericTypeConverterMixin, LongConverter):
-    _immutable_ = True
-    libffitype = libffi.types.pointer
-    typecode = 'r'
-
-    def convert_argument(self, space, w_obj, address, call_local):
-        x = rffi.cast(self.c_ptrtype, address)
-        x[0] = self._unwrap_object(space, w_obj)
-        ba = rffi.cast(rffi.CCHARP, address)
-        ba[capi.c_function_arg_typeoffset()] = self.typecode
-
-class LongLongConverter(IntTypeConverterMixin, TypeConverter):
-    _immutable_ = True
-    libffitype = libffi.types.slong
-    c_type     = rffi.LONGLONG
-    c_ptrtype  = rffi.LONGLONGP
-
-    def __init__(self, space, default):
-        self.default = rffi.cast(self.c_type, capi.c_strtoll(default))
-
-    def _unwrap_object(self, space, w_obj):
-        return space.r_longlong_w(w_obj)
-
-class ConstLongLongRefConverter(ConstRefNumericTypeConverterMixin, LongLongConverter):
-    _immutable_ = True
-    libffitype = libffi.types.pointer
-    typecode = 'r'
-
-    def convert_argument(self, space, w_obj, address, call_local):
-        x = rffi.cast(self.c_ptrtype, address)
-        x[0] = self._unwrap_object(space, w_obj)
-        ba = rffi.cast(rffi.CCHARP, address)
-        ba[capi.c_function_arg_typeoffset()] = self.typecode
-
-class UnsignedLongConverter(IntTypeConverterMixin, TypeConverter):
-    _immutable_ = True
-    libffitype = libffi.types.ulong
-    c_type     = rffi.ULONG
-    c_ptrtype  = rffi.ULONGP
-
-    def __init__(self, space, default):
-        self.default = rffi.cast(self.c_type, capi.c_strtoull(default))
-
-    def _unwrap_object(self, space, w_obj):
-        return space.uint_w(w_obj)
-
-class UnsignedLongLongConverter(IntTypeConverterMixin, TypeConverter):
-    _immutable_ = True
-    libffitype = libffi.types.ulong
-    c_type     = rffi.ULONGLONG
-    c_ptrtype  = rffi.ULONGLONGP
-
-    def __init__(self, space, default):
-        self.default = rffi.cast(self.c_type, capi.c_strtoull(default))
-
-    def _unwrap_object(self, space, w_obj):
-        return space.r_ulonglong_w(w_obj)
-
-
-class FloatConverter(FloatTypeConverterMixin, TypeConverter):
-    _immutable_ = True
-    libffitype = libffi.types.float
-    c_type     = rffi.FLOAT
-    c_ptrtype  = rffi.FLOATP
-    typecode   = 'f'
 
     def __init__(self, space, default):
         if default:
@@ -446,9 +304,6 @@
             fval = float(0.)
         self.default = r_singlefloat(fval)
 
-    def _unwrap_object(self, space, w_obj):
-        return r_singlefloat(space.float_w(w_obj))
-
     def from_memory(self, space, w_obj, w_pycppclass, offset):
         address = self._get_raw_address(space, w_obj, offset)
         rffiptr = rffi.cast(self.c_ptrtype, address)
@@ -463,12 +318,8 @@
         from pypy.module.cppyy.interp_cppyy import FastCallNotPossible
         raise FastCallNotPossible
 
-class DoubleConverter(FloatTypeConverterMixin, TypeConverter):
+class DoubleConverter(ffitypes.typeid(rffi.DOUBLE), FloatTypeConverterMixin, TypeConverter):
     _immutable_ = True
-    libffitype = libffi.types.double
-    c_type     = rffi.DOUBLE
-    c_ptrtype  = rffi.DOUBLEP
-    typecode   = 'd'
 
     def __init__(self, space, default):
         if default:
@@ -476,9 +327,6 @@
         else:
             self.default = rffi.cast(self.c_type, 0.)
 
-    def _unwrap_object(self, space, w_obj):
-        return space.float_w(w_obj)
-
 class ConstDoubleRefConverter(ConstRefNumericTypeConverterMixin, DoubleConverter):
     _immutable_ = True
     libffitype = libffi.types.pointer
@@ -750,8 +598,8 @@
         elif compound == "":
             return InstanceConverter(space, cppclass)
     elif capi.c_is_enum(clean_name):
-        return UnsignedIntConverter(space, default)
-    
+        return _converters['unsigned'](space, default)
+
     #   5) void converter, which fails on use
     #
     # return a void converter here, so that the class can be build even
@@ -761,16 +609,6 @@
 
 _converters["bool"]                     = BoolConverter
 _converters["char"]                     = CharConverter
-_converters["short"]                    = ShortConverter
-_converters["unsigned short"]           = UnsignedShortConverter
-_converters["int"]                      = IntConverter
-_converters["unsigned"]                 = UnsignedIntConverter
-_converters["long"]                     = LongConverter
-_converters["const long&"]              = ConstLongRefConverter
-_converters["unsigned long"]            = UnsignedLongConverter
-_converters["long long"]                = LongLongConverter
-_converters["const long long&"]         = ConstLongLongRefConverter
-_converters["unsigned long long"]       = UnsignedLongLongConverter
 _converters["float"]                    = FloatConverter
 _converters["const float&"]             = ConstFloatRefConverter
 _converters["double"]                   = DoubleConverter
@@ -787,57 +625,74 @@
 
 _converters["PyObject*"]                         = PyObjectConverter
 
-# add the set of aliased names
-def _add_aliased_converters():
+# add basic (builtin) converters
+def _build_basic_converters():
     "NOT_RPYTHON"
-    alias_info = (
-        ("char",                            ("unsigned char",)),
-
-        ("short",                           ("short int",)),
-        ("unsigned short",                  ("unsigned short int",)),
-        ("unsigned",                        ("unsigned int",)),
-        ("long",                            ("long int",)),
-        ("const long&",                     ("const long int&",)),
-        ("unsigned long",                   ("unsigned long int",)),
-        ("long long",                       ("long long int",)),
-        ("const long long&",                ("const long long int&",)),
-        ("unsigned long long",              ("unsigned long long int",)),
-
-        ("const char*",                     ("char*",)),
-
-        ("std::basic_string<char>",         ("string",)),
-        ("const std::basic_string<char>&",  ("const string&",)),
-        ("std::basic_string<char>&",        ("string&",)),
-
-        ("PyObject*",                       ("_object*",)),
+    # signed types (use strtoll in setting of default in __init__)
+    type_info = (
+        (rffi.SHORT,      ("short", "short int")),
+        (rffi.INT,        ("int",)),
     )
 
-    for info in alias_info:
-        for name in info[1]:
-            _converters[name] = _converters[info[0]]
-_add_aliased_converters()
+    # constref converters exist only b/c the stubs take constref by value, whereas
+    # libffi takes them by pointer (hence it needs the fast-path in testing); note
+    # that this is list is not complete, as some classes are specialized
 
-# constref converters exist only b/c the stubs take constref by value, whereas
-# libffi takes them by pointer (hence it needs the fast-path in testing); note
-# that this is list is not complete, as some classes are specialized
-def _build_constref_converters():
-    "NOT_RPYTHON"
+    for c_type, names in type_info:
+        class BasicConverter(ffitypes.typeid(c_type), IntTypeConverterMixin, TypeConverter):
+            _immutable_ = True
+            def __init__(self, space, default):
+                self.default = rffi.cast(self.c_type, capi.c_strtoll(default))
+        class ConstRefConverter(ConstRefNumericTypeConverterMixin, BasicConverter):
+            _immutable_ = True
+            libffitype = libffi.types.pointer
+        for name in names:
+            _converters[name] = BasicConverter
+            _converters["const "+name+"&"] = ConstRefConverter
+
     type_info = (
-        (ShortConverter,            ("short int", "short")),
-        (UnsignedShortConverter,    ("unsigned short int", "unsigned short")),
-        (IntConverter,              ("int",)),
-        (UnsignedIntConverter,      ("unsigned int", "unsigned")),
-        (UnsignedLongConverter,     ("unsigned long int", "unsigned long")),
-        (UnsignedLongLongConverter, ("unsigned long long int", "unsigned long long")),
+        (rffi.LONG,       ("long", "long int")),
+        (rffi.LONGLONG,   ("long long", "long long int")),
     )
 
-    for info in type_info:
-        class ConstRefConverter(ConstRefNumericTypeConverterMixin, info[0]):
+    for c_type, names in type_info:
+        class BasicConverter(ffitypes.typeid(c_type), IntTypeConverterMixin, TypeConverter):
+            _immutable_ = True
+            def __init__(self, space, default):
+                self.default = rffi.cast(self.c_type, capi.c_strtoll(default))
+        class ConstRefConverter(ConstRefNumericTypeConverterMixin, BasicConverter):
             _immutable_ = True
             libffitype = libffi.types.pointer
-        for name in info[1]:
+            typecode = 'r'
+            def convert_argument(self, space, w_obj, address, call_local):
+                x = rffi.cast(self.c_ptrtype, address)
+                x[0] = self._unwrap_object(space, w_obj)
+                ba = rffi.cast(rffi.CCHARP, address)
+                ba[capi.c_function_arg_typeoffset()] = self.typecode
+        for name in names:
+            _converters[name] = BasicConverter
             _converters["const "+name+"&"] = ConstRefConverter
-_build_constref_converters()
+
+    # unsigned integer types (use strtoull in setting of default in __init__)
+    type_info = (
+        (rffi.USHORT,     ("unsigned short", "unsigned short int")),
+        (rffi.UINT,       ("unsigned", "unsigned int")),
+        (rffi.ULONG,      ("unsigned long", "unsigned long int")),
+        (rffi.ULONGLONG,  ("unsigned long long", "unsigned long long int")),
+    )
+
+    for c_type, names in type_info:
+        class BasicConverter(ffitypes.typeid(c_type), IntTypeConverterMixin, TypeConverter):
+            _immutable_ = True
+            def __init__(self, space, default):
+                self.default = rffi.cast(self.c_type, capi.c_strtoull(default))
+        class ConstRefConverter(ConstRefNumericTypeConverterMixin, BasicConverter):
+            _immutable_ = True
+            libffitype = libffi.types.pointer
+        for name in names:
+            _converters[name] = BasicConverter
+            _converters["const "+name+"&"] = ConstRefConverter
+_build_basic_converters()
 
 # create the array and pointer converters; all real work is in the mixins
 def _build_array_converters():
@@ -854,16 +709,35 @@
         ('d', rffi.sizeof(rffi.DOUBLE), ("double",)),
     )
 
-    for info in array_info:
+    for tcode, tsize, names in array_info:
         class ArrayConverter(ArrayTypeConverterMixin, TypeConverter):
             _immutable_ = True
-            typecode = info[0]
-            typesize = info[1]
+            typecode = tcode
+            typesize = tsize
         class PtrConverter(PtrTypeConverterMixin, TypeConverter):
             _immutable_ = True
-            typecode = info[0]
-            typesize = info[1]
-        for name in info[2]:
+            typecode = tcode
+            typesize = tsize
+        for name in names:
             _a_converters[name+'[]'] = ArrayConverter
             _a_converters[name+'*']  = PtrConverter
 _build_array_converters()
+
+# add another set of aliased names
+def _add_aliased_converters():
+    "NOT_RPYTHON"
+    aliases = (
+        ("char",                            "unsigned char"),
+        ("const char*",                     "char*"),
+
+        ("std::basic_string<char>",         "string"),
+        ("const std::basic_string<char>&",  "const string&"),
+        ("std::basic_string<char>&",        "string&"),
+
+        ("PyObject*",                       "_object*"),
+    )
+ 
+    for c_type, alias in aliases:
+        _converters[alias] = _converters[c_type]
+_add_aliased_converters()
+
diff --git a/pypy/module/cppyy/executor.py b/pypy/module/cppyy/executor.py
--- a/pypy/module/cppyy/executor.py
+++ b/pypy/module/cppyy/executor.py
@@ -8,7 +8,7 @@
 from pypy.module._rawffi.interp_rawffi import unpack_simple_shape
 from pypy.module._rawffi.array import W_Array
 
-from pypy.module.cppyy import helper, capi
+from pypy.module.cppyy import helper, capi, ffitypes
 
 # Executor objects are used to dispatch C++ methods. They are defined by their
 # return type only: arguments are converted by Converter objects, and Executors
@@ -83,6 +83,32 @@
         result = libffifunc.call(argchain, self.c_type)
         return space.wrap(result)
 
+class NumericRefExecutorMixin(object):
+    _mixin_ = True
+    _immutable_ = True
+
+    def __init__(self, space, extra):
+        FunctionExecutor.__init__(self, space, extra)
+        self.do_assign = False
+        self.item = rffi.cast(self.c_type, 0)
+
+    def set_item(self, space, w_item):
+        self.item = self._unwrap_object(space, w_item)
+        self.do_assign = True
+
+    def _wrap_result(self, space, rffiptr):
+        if self.do_assign:
+            rffiptr[0] = self.item
+        return space.wrap(rffiptr[0])   # all paths, for rtyper
+
+    def execute(self, space, cppmethod, cppthis, num_args, args):
+        result = rffi.cast(self.c_ptrtype, 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, self.c_ptrtype)
+        return self._wrap_result(space, result)
+
 
 class BoolExecutor(FunctionExecutor):
     _immutable_ = True
@@ -112,32 +138,6 @@
         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
@@ -162,32 +162,6 @@
         result = libffifunc.call(argchain, rffi.FLOAT)
         return space.wrap(float(result))
 
-class DoubleRefExecutor(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.DOUBLE, 0)
-
-    def set_item(self, space, w_item):
-        self.item = rffi.cast(rffi.DOUBLE, space.float_w(w_item))
-        self.do_assign = True
-
-    def _wrap_result(self, space, dptr):
-        if self.do_assign:
-            dptr[0] = self.item
-        return space.wrap(dptr[0])      # all paths, for rtyper
-
-    def execute(self, space, cppmethod, cppthis, num_args, args):
-        result = rffi.cast(rffi.DOUBLEP, 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.DOUBLEP)
-        return self._wrap_result(space, result)
-
 
 class CStringExecutor(FunctionExecutor):
     _immutable_ = True
@@ -358,14 +332,14 @@
 _executors["bool"]                = BoolExecutor
 _executors["const char*"]         = CStringExecutor
 _executors["const int&"]          = ConstIntRefExecutor
-_executors["int&"]                = IntRefExecutor
 _executors["float"]               = FloatExecutor
-_executors["double&"]             = DoubleRefExecutor
 
 _executors["constructor"]         = ConstructorExecutor
 
-# special cases (note: CINT backend requires the simple name 'string')
-_executors["std::basic_string<char>"]        = StdStringExecutor
+# special cases
+_executors["std::basic_string<char>"]         = StdStringExecutor
+_executors["const std::basic_string<char>&"]  = StdStringExecutor
+_executors["std::basic_string<char>&"]        = StdStringExecutor    # TODO: shouldn't copy
 
 _executors["PyObject*"]           = PyObjectExecutor
 
@@ -373,41 +347,29 @@
 def _build_basic_executors():
     "NOT_RPYTHON"
     type_info = (
-        (rffi.CHAR,       libffi.types.schar,   capi.c_call_c,   ("char", "unsigned char")),
-        (rffi.SHORT,      libffi.types.sshort,  capi.c_call_h,   ("short", "short int", "unsigned short", "unsigned short int")),
-        (rffi.INT,        libffi.types.sint,    capi.c_call_i,   ("int",)),
-        (rffi.UINT,       libffi.types.uint,    capi.c_call_l,   ("unsigned", "unsigned int")),
-        (rffi.LONG,       libffi.types.slong,   capi.c_call_l,   ("long", "long int")),
-        (rffi.ULONG,      libffi.types.ulong,   capi.c_call_l,   ("unsigned long", "unsigned long int")),
-        (rffi.LONGLONG,   libffi.types.sint64,  capi.c_call_ll,  ("long long", "long long int")),
-        (rffi.ULONGLONG,  libffi.types.uint64,  capi.c_call_ll,  ("unsigned long long", "unsigned long long int")),
-        (rffi.DOUBLE,     libffi.types.double,  capi.c_call_d,   ("double",))
+        (rffi.CHAR,       capi.c_call_c,   ("char", "unsigned char")),
+        (rffi.SHORT,      capi.c_call_h,   ("short", "short int", "unsigned short", "unsigned short int")),
+        (rffi.INT,        capi.c_call_i,   ("int",)),
+        (rffi.UINT,       capi.c_call_l,   ("unsigned", "unsigned int")),
+        (rffi.LONG,       capi.c_call_l,   ("long", "long int")),
+        (rffi.ULONG,      capi.c_call_l,   ("unsigned long", "unsigned long int")),
+        (rffi.LONGLONG,   capi.c_call_ll,  ("long long", "long long int")),
+        (rffi.ULONGLONG,  capi.c_call_ll,  ("unsigned long long", "unsigned long long int")),
+        (rffi.DOUBLE,     capi.c_call_d,   ("double",))
     )
 
-    for t_rffi, t_ffi, stub, names in type_info:
-        class BasicExecutor(NumericExecutorMixin, FunctionExecutor):
+    for c_type, stub, names in type_info:
+        class BasicExecutor(ffitypes.typeid(c_type), NumericExecutorMixin, FunctionExecutor):
             _immutable_ = True
-            libffitype  = t_ffi
-            c_type      = t_rffi
             c_stubcall  = staticmethod(stub)
+        class BasicRefExecutor(ffitypes.typeid(c_type), NumericRefExecutorMixin, FunctionExecutor):
+            _immutable_ = True
+            libffitype = libffi.types.pointer
         for name in names:
-            _executors[name] = BasicExecutor
+            _executors[name]     = BasicExecutor
+            _executors[name+'&'] = BasicRefExecutor
 _build_basic_executors()
 
-# add the set of aliased names
-def _add_aliased_executors():
-    "NOT_RPYTHON"
-    alias_info = (
-        ("const char*",                     ("char*",)),
-        ("std::basic_string<char>",         ("string",)),
-        ("PyObject*",                       ("_object*",)),
-    )
-
-    for info in alias_info:
-        for name in info[1]:
-            _executors[name] = _executors[info[0]]
-_add_aliased_executors()
-
 # create the pointer executors; all real work is in the PtrTypeExecutor, since
 # all pointer types are of the same size
 def _build_ptr_executors():
@@ -424,10 +386,23 @@
         ('d', ("double",)),
     )
 
-    for info in ptr_info:
+    for tcode, names in ptr_info:
         class PtrExecutor(PtrTypeExecutor):
             _immutable_ = True
-            typecode = info[0]
-        for name in info[1]:
+            typecode = tcode
+        for name in names:
             _executors[name+'*'] = PtrExecutor
 _build_ptr_executors()
+
+# add another set of aliased names
+def _add_aliased_executors():
+    "NOT_RPYTHON"
+    aliases = (
+        ("const char*",                     "char*"),
+        ("std::basic_string<char>",         "string"),
+        ("PyObject*",                       "_object*"),
+    )
+
+    for c_type, alias in aliases:
+        _executors[alias] = _executors[c_type]
+_add_aliased_executors()
diff --git a/pypy/module/cppyy/ffitypes.py b/pypy/module/cppyy/ffitypes.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/cppyy/ffitypes.py
@@ -0,0 +1,155 @@
+from pypy.interpreter.error import OperationError
+
+from pypy.rpython.lltypesystem import rffi
+from pypy.rlib.rarithmetic import r_singlefloat
+from pypy.rlib import libffi, rfloat
+
+# Mixins to share between converter and executor classes (in converter.py and
+# executor.py, respectively). Basically these mixins allow grouping of the
+# sets of libffi, rffi, and different space unwrapping calls. To get the right
+# mixin, a non-RPython function typeid() is used.
+
+
+class CharTypeMixin(object):
+    _mixin_     = True
+    _immutable_ = True
+    libffitype  = libffi.types.schar
+    c_type      = rffi.CHAR
+    c_ptrtype   = rffi.CCHARP           # there's no such thing as rffi.CHARP
+
+    def _unwrap_object(self, space, w_value):
+        # allow int to pass to char and make sure that str is of length 1
+        if space.isinstance_w(w_value, space.w_int):
+            ival = space.c_int_w(w_value)
+            if ival < 0 or 256 <= ival:
+                raise OperationError(space.w_ValueError,
+                                     space.wrap("char arg not in range(256)"))
+
+            value = rffi.cast(rffi.CHAR, space.c_int_w(w_value))
+        else:
+            value = space.str_w(w_value)
+
+        if len(value) != 1:  
+            raise OperationError(space.w_ValueError,
+                                 space.wrap("char expected, got string of size %d" % len(value)))
+        return value[0] # turn it into a "char" to the annotator
+
+class ShortTypeMixin(object):
+    _mixin_     = True
+    _immutable_ = True
+    libffitype  = libffi.types.sshort
+    c_type      = rffi.SHORT
+    c_ptrtype   = rffi.SHORTP
+
+    def _unwrap_object(self, space, w_obj):
+        return rffi.cast(rffi.SHORT, space.int_w(w_obj))
+
+class UShortTypeMixin(object):
+    _mixin_     = True
+    _immutable_ = True
+    libffitype  = libffi.types.ushort
+    c_type      = rffi.USHORT
+    c_ptrtype   = rffi.USHORTP
+
+    def _unwrap_object(self, space, w_obj):
+        return rffi.cast(self.c_type, space.int_w(w_obj))
+
+class IntTypeMixin(object):
+    _mixin_     = True
+    _immutable_ = True
+    libffitype  = libffi.types.sint
+    c_type      = rffi.INT
+    c_ptrtype   = rffi.INTP
+
+    def _unwrap_object(self, space, w_obj):
+        return rffi.cast(self.c_type, space.c_int_w(w_obj))
+
+class UIntTypeMixin(object):
+    _mixin_     = True
+    _immutable_ = True
+    libffitype  = libffi.types.uint
+    c_type      = rffi.UINT
+    c_ptrtype   = rffi.UINTP
+
+    def _unwrap_object(self, space, w_obj):
+        return rffi.cast(self.c_type, space.uint_w(w_obj))
+
+class LongTypeMixin(object):
+    _mixin_     = True
+    _immutable_ = True
+    libffitype = libffi.types.slong
+    c_type     =  rffi.LONG
+    c_ptrtype   = rffi.LONGP
+
+    def _unwrap_object(self, space, w_obj):
+        return space.int_w(w_obj)
+
+class ULongTypeMixin(object):
+    _mixin_     = True
+    _immutable_ = True
+    libffitype = libffi.types.ulong
+    c_type     = rffi.ULONG
+    c_ptrtype  = rffi.ULONGP
+
+    def _unwrap_object(self, space, w_obj):
+        return space.uint_w(w_obj)
+
+class LongLongTypeMixin(object):
+    _mixin_     = True
+    _immutable_ = True
+    libffitype  = libffi.types.sint64
+    c_type      = rffi.LONGLONG
+    c_ptrtype   = rffi.LONGLONGP
+
+    def _unwrap_object(self, space, w_obj):
+        return space.r_longlong_w(w_obj)
+
+class ULongLongTypeMixin(object):
+    _mixin_     = True
+    _immutable_ = True
+    libffitype = libffi.types.uint64
+    c_type     = rffi.ULONGLONG
+    c_ptrtype  = rffi.ULONGLONGP
+
+    def _unwrap_object(self, space, w_obj):
+        return space.r_ulonglong_w(w_obj)
+
+class FloatTypeMixin(object):
+    _mixin_     = True
+    _immutable_ = True
+    libffitype  = libffi.types.float
+    c_type      = rffi.FLOAT
+    c_ptrtype   = rffi.FLOATP
+    typecode    = 'f'
+
+    def _unwrap_object(self, space, w_obj):
+        return r_singlefloat(space.float_w(w_obj))
+
+class DoubleTypeMixin(object):
+    _mixin_     = True
+    _immutable_ = True
+    libffitype  = libffi.types.double
+    c_type      = rffi.DOUBLE
+    c_ptrtype   = rffi.DOUBLEP
+    typecode    = 'd'
+
+    def _unwrap_object(self, space, w_obj):
+        return space.float_w(w_obj)
+
+
+def typeid(c_type):
+    "NOT_RPYTHON"
+    if c_type == rffi.CHAR:       return CharTypeMixin
+    if c_type == rffi.SHORT:      return ShortTypeMixin
+    if c_type == rffi.USHORT:     return UShortTypeMixin
+    if c_type == rffi.INT:        return IntTypeMixin
+    if c_type == rffi.UINT:       return UIntTypeMixin
+    if c_type == rffi.LONG:       return LongTypeMixin
+    if c_type == rffi.ULONG:      return ULongTypeMixin
+    if c_type == rffi.LONGLONG:   return LongLongTypeMixin
+    if c_type == rffi.ULONGLONG:  return ULongLongTypeMixin
+    if c_type == rffi.FLOAT:      return FloatTypeMixin
+    if c_type == rffi.DOUBLE:     return DoubleTypeMixin
+
+    # should never get here
+    raise TypeError("unknown rffi type: %s" % c_type)


More information about the pypy-commit mailing list