Home | History | Annotate | Download | only in Compiler
      1 #
      2 #   Tables describing slots in the CPython type object
      3 #   and associated know-how.
      4 #
      5 
      6 import Naming
      7 import PyrexTypes
      8 import StringEncoding
      9 
     10 invisible = ['__cinit__', '__dealloc__', '__richcmp__',
     11              '__nonzero__', '__bool__']
     12 
     13 class Signature(object):
     14     #  Method slot signature descriptor.
     15     #
     16     #  has_dummy_arg      boolean
     17     #  has_generic_args   boolean
     18     #  fixed_arg_format   string
     19     #  ret_format         string
     20     #  error_value        string
     21     #
     22     #  The formats are strings made up of the following
     23     #  characters:
     24     #
     25     #    'O'  Python object
     26     #    'T'  Python object of the type of 'self'
     27     #    'v'  void
     28     #    'p'  void *
     29     #    'P'  void **
     30     #    'i'  int
     31     #    'b'  bint
     32     #    'I'  int *
     33     #    'l'  long
     34     #    'f'  float
     35     #    'd'  double
     36     #    'h'  Py_hash_t
     37     #    'z'  Py_ssize_t
     38     #    'Z'  Py_ssize_t *
     39     #    's'  char *
     40     #    'S'  char **
     41     #    'r'  int used only to signal exception
     42     #    'B'  Py_buffer *
     43     #    '-'  dummy 'self' argument (not used)
     44     #    '*'  rest of args passed as generic Python
     45     #           arg tuple and kw dict (must be last
     46     #           char in format string)
     47 
     48     format_map = {
     49         'O': PyrexTypes.py_object_type,
     50         'v': PyrexTypes.c_void_type,
     51         'p': PyrexTypes.c_void_ptr_type,
     52         'P': PyrexTypes.c_void_ptr_ptr_type,
     53         'i': PyrexTypes.c_int_type,
     54         'b': PyrexTypes.c_bint_type,
     55         'I': PyrexTypes.c_int_ptr_type,
     56         'l': PyrexTypes.c_long_type,
     57         'f': PyrexTypes.c_float_type,
     58         'd': PyrexTypes.c_double_type,
     59         'h': PyrexTypes.c_py_hash_t_type,
     60         'z': PyrexTypes.c_py_ssize_t_type,
     61         'Z': PyrexTypes.c_py_ssize_t_ptr_type,
     62         's': PyrexTypes.c_char_ptr_type,
     63         'S': PyrexTypes.c_char_ptr_ptr_type,
     64         'r': PyrexTypes.c_returncode_type,
     65         'B': PyrexTypes.c_py_buffer_ptr_type,
     66         # 'T', '-' and '*' are handled otherwise
     67         # and are not looked up in here
     68     }
     69 
     70     type_to_format_map = dict([(type_, format_)
     71                                    for format_, type_ in format_map.iteritems()])
     72 
     73     error_value_map = {
     74         'O': "NULL",
     75         'T': "NULL",
     76         'i': "-1",
     77         'b': "-1",
     78         'l': "-1",
     79         'r': "-1",
     80         'h': "-1",
     81         'z': "-1",
     82     }
     83 
     84     def __init__(self, arg_format, ret_format):
     85         self.has_dummy_arg = 0
     86         self.has_generic_args = 0
     87         if arg_format[:1] == '-':
     88             self.has_dummy_arg = 1
     89             arg_format = arg_format[1:]
     90         if arg_format[-1:] == '*':
     91             self.has_generic_args = 1
     92             arg_format = arg_format[:-1]
     93         self.fixed_arg_format = arg_format
     94         self.ret_format = ret_format
     95         self.error_value = self.error_value_map.get(ret_format, None)
     96         self.exception_check = ret_format != 'r' and self.error_value is not None
     97         self.is_staticmethod = False
     98 
     99     def num_fixed_args(self):
    100         return len(self.fixed_arg_format)
    101 
    102     def is_self_arg(self, i):
    103         # argument is 'self' for methods or 'class' for classmethods
    104         return self.fixed_arg_format[i] == 'T'
    105 
    106     def returns_self_type(self):
    107         # return type is same as 'self' argument type
    108         return self.ret_format == 'T'
    109 
    110     def fixed_arg_type(self, i):
    111         return self.format_map[self.fixed_arg_format[i]]
    112 
    113     def return_type(self):
    114         return self.format_map[self.ret_format]
    115 
    116     def format_from_type(self, arg_type):
    117         if arg_type.is_pyobject:
    118             arg_type = PyrexTypes.py_object_type
    119         return self.type_to_format_map[arg_type]
    120 
    121     def exception_value(self):
    122         return self.error_value_map.get(self.ret_format)
    123 
    124     def function_type(self, self_arg_override=None):
    125         #  Construct a C function type descriptor for this signature
    126         args = []
    127         for i in xrange(self.num_fixed_args()):
    128             if self_arg_override is not None and self.is_self_arg(i):
    129                 assert isinstance(self_arg_override, PyrexTypes.CFuncTypeArg)
    130                 args.append(self_arg_override)
    131             else:
    132                 arg_type = self.fixed_arg_type(i)
    133                 args.append(PyrexTypes.CFuncTypeArg("", arg_type, None))
    134         if self_arg_override is not None and self.returns_self_type():
    135             ret_type = self_arg_override.type
    136         else:
    137             ret_type = self.return_type()
    138         exc_value = self.exception_value()
    139         return PyrexTypes.CFuncType(
    140             ret_type, args, exception_value=exc_value,
    141             exception_check=self.exception_check)
    142 
    143     def method_flags(self):
    144         if self.ret_format == "O":
    145             full_args = self.fixed_arg_format
    146             if self.has_dummy_arg:
    147                 full_args = "O" + full_args
    148             if full_args in ["O", "T"]:
    149                 if self.has_generic_args:
    150                     return [method_varargs, method_keywords]
    151                 else:
    152                     return [method_noargs]
    153             elif full_args in ["OO", "TO"] and not self.has_generic_args:
    154                 return [method_onearg]
    155 
    156             if self.is_staticmethod:
    157                 return [method_varargs, method_keywords]
    158         return None
    159 
    160 
    161 class SlotDescriptor(object):
    162     #  Abstract base class for type slot descriptors.
    163     #
    164     #  slot_name    string           Member name of the slot in the type object
    165     #  is_initialised_dynamically    Is initialised by code in the module init function
    166     #  is_inherited                  Is inherited by subtypes (see PyType_Ready())
    167     #  py3                           Indicates presence of slot in Python 3
    168     #  py2                           Indicates presence of slot in Python 2
    169     #  ifdef                         Full #ifdef string that slot is wrapped in. Using this causes py3, py2 and flags to be ignored.)
    170 
    171     def __init__(self, slot_name, dynamic=False, inherited=False,
    172                  py3=True, py2=True, ifdef=None):
    173         self.slot_name = slot_name
    174         self.is_initialised_dynamically = dynamic
    175         self.is_inherited = inherited
    176         self.ifdef = ifdef
    177         self.py3 = py3
    178         self.py2 = py2
    179 
    180     def preprocessor_guard_code(self):
    181         ifdef = self.ifdef
    182         py2 = self.py2
    183         py3 = self.py3
    184         guard = None
    185         if ifdef:
    186             guard = ("#if %s" % ifdef)
    187         elif not py3 or py3 == '<RESERVED>':
    188             guard = ("#if PY_MAJOR_VERSION < 3")
    189         elif not py2:
    190             guard = ("#if PY_MAJOR_VERSION >= 3")
    191         return guard
    192 
    193     def generate(self, scope, code):
    194         end_pypy_guard = False
    195         if self.is_initialised_dynamically:
    196             value = "0"
    197         else:
    198             value = self.slot_code(scope)
    199             if value == "0" and self.is_inherited:
    200                 # PyPy currently has a broken PyType_Ready() that fails to
    201                 # inherit some slots.  To work around this, we explicitly
    202                 # set inherited slots here, but only in PyPy since CPython
    203                 # handles this better than we do.
    204                 inherited_value = value
    205                 current_scope = scope
    206                 while (inherited_value == "0"
    207                        and current_scope.parent_type
    208                        and current_scope.parent_type.base_type
    209                        and current_scope.parent_type.base_type.scope):
    210                     current_scope = current_scope.parent_type.base_type.scope
    211                     inherited_value = self.slot_code(current_scope)
    212                 if inherited_value != "0":
    213                     code.putln("#if CYTHON_COMPILING_IN_PYPY")
    214                     code.putln("%s, /*%s*/" % (inherited_value, self.slot_name))
    215                     code.putln("#else")
    216                     end_pypy_guard = True
    217         preprocessor_guard = self.preprocessor_guard_code()
    218         if preprocessor_guard:
    219             code.putln(preprocessor_guard)
    220         code.putln("%s, /*%s*/" % (value, self.slot_name))
    221         if self.py3 == '<RESERVED>':
    222             code.putln("#else")
    223             code.putln("0, /*reserved*/")
    224         if preprocessor_guard:
    225             code.putln("#endif")
    226         if end_pypy_guard:
    227             code.putln("#endif")
    228 
    229     # Some C implementations have trouble statically
    230     # initialising a global with a pointer to an extern
    231     # function, so we initialise some of the type slots
    232     # in the module init function instead.
    233 
    234     def generate_dynamic_init_code(self, scope, code):
    235         if self.is_initialised_dynamically:
    236             value = self.slot_code(scope)
    237             if value != "0":
    238                 code.putln("%s.%s = %s;" % (
    239                     scope.parent_type.typeobj_cname,
    240                     self.slot_name,
    241                     value
    242                     )
    243                 )
    244 
    245 
    246 class FixedSlot(SlotDescriptor):
    247     #  Descriptor for a type slot with a fixed value.
    248     #
    249     #  value        string
    250 
    251     def __init__(self, slot_name, value, py3=True, py2=True, ifdef=None):
    252         SlotDescriptor.__init__(self, slot_name, py3=py3, py2=py2, ifdef=ifdef)
    253         self.value = value
    254 
    255     def slot_code(self, scope):
    256         return self.value
    257 
    258 
    259 class EmptySlot(FixedSlot):
    260     #  Descriptor for a type slot whose value is always 0.
    261 
    262     def __init__(self, slot_name, py3=True, py2=True, ifdef=None):
    263         FixedSlot.__init__(self, slot_name, "0", py3=py3, py2=py2, ifdef=ifdef)
    264 
    265 
    266 class MethodSlot(SlotDescriptor):
    267     #  Type slot descriptor for a user-definable method.
    268     #
    269     #  signature    Signature
    270     #  method_name  string           The __xxx__ name of the method
    271     #  alternatives [string]         Alternative list of __xxx__ names for the method
    272 
    273     def __init__(self, signature, slot_name, method_name, fallback=None,
    274                  py3=True, py2=True, ifdef=None, inherited=True):
    275         SlotDescriptor.__init__(self, slot_name, py3=py3, py2=py2,
    276                                 ifdef=ifdef, inherited=inherited)
    277         self.signature = signature
    278         self.slot_name = slot_name
    279         self.method_name = method_name
    280         self.alternatives = []
    281         method_name_to_slot[method_name] = self
    282         #
    283         if fallback:
    284             self.alternatives.append(fallback)
    285         for alt in (self.py2, self.py3):
    286             if isinstance(alt, (tuple, list)):
    287                 slot_name, method_name = alt
    288                 self.alternatives.append(method_name)
    289                 method_name_to_slot[method_name] = self
    290 
    291     def slot_code(self, scope):
    292         entry = scope.lookup_here(self.method_name)
    293         if entry and entry.func_cname:
    294             return entry.func_cname
    295         for method_name in self.alternatives:
    296             entry = scope.lookup_here(method_name)
    297             if entry and entry.func_cname:
    298                 return entry.func_cname
    299         return "0"
    300 
    301 
    302 class InternalMethodSlot(SlotDescriptor):
    303     #  Type slot descriptor for a method which is always
    304     #  synthesized by Cython.
    305     #
    306     #  slot_name    string           Member name of the slot in the type object
    307 
    308     def __init__(self, slot_name, **kargs):
    309         SlotDescriptor.__init__(self, slot_name, **kargs)
    310 
    311     def slot_code(self, scope):
    312         return scope.mangle_internal(self.slot_name)
    313 
    314 
    315 class GCDependentSlot(InternalMethodSlot):
    316     #  Descriptor for a slot whose value depends on whether
    317     #  the type participates in GC.
    318 
    319     def __init__(self, slot_name, **kargs):
    320         InternalMethodSlot.__init__(self, slot_name, **kargs)
    321 
    322     def slot_code(self, scope):
    323         if not scope.needs_gc():
    324             return "0"
    325         if not scope.has_cyclic_pyobject_attrs:
    326             # if the type does not have GC relevant object attributes, it can
    327             # delegate GC methods to its parent - iff the parent functions
    328             # are defined in the same module
    329             parent_type_scope = scope.parent_type.base_type.scope
    330             if scope.parent_scope is parent_type_scope.parent_scope:
    331                 entry = scope.parent_scope.lookup_here(scope.parent_type.base_type.name)
    332                 if entry.visibility != 'extern':
    333                     return self.slot_code(parent_type_scope)
    334         return InternalMethodSlot.slot_code(self, scope)
    335 
    336 
    337 class GCClearReferencesSlot(GCDependentSlot):
    338 
    339     def slot_code(self, scope):
    340         if scope.needs_tp_clear():
    341             return GCDependentSlot.slot_code(self, scope)
    342         return "0"
    343 
    344 
    345 class ConstructorSlot(InternalMethodSlot):
    346     #  Descriptor for tp_new and tp_dealloc.
    347 
    348     def __init__(self, slot_name, method, **kargs):
    349         InternalMethodSlot.__init__(self, slot_name, **kargs)
    350         self.method = method
    351 
    352     def slot_code(self, scope):
    353         if (self.slot_name != 'tp_new'
    354                 and scope.parent_type.base_type
    355                 and not scope.has_pyobject_attrs
    356                 and not scope.has_memoryview_attrs
    357                 and not scope.lookup_here(self.method)):
    358             # if the type does not have object attributes, it can
    359             # delegate GC methods to its parent - iff the parent
    360             # functions are defined in the same module
    361             parent_type_scope = scope.parent_type.base_type.scope
    362             if scope.parent_scope is parent_type_scope.parent_scope:
    363                 entry = scope.parent_scope.lookup_here(scope.parent_type.base_type.name)
    364                 if entry.visibility != 'extern':
    365                     return self.slot_code(parent_type_scope)
    366         return InternalMethodSlot.slot_code(self, scope)
    367 
    368 
    369 class SyntheticSlot(InternalMethodSlot):
    370     #  Type slot descriptor for a synthesized method which
    371     #  dispatches to one or more user-defined methods depending
    372     #  on its arguments. If none of the relevant methods are
    373     #  defined, the method will not be synthesized and an
    374     #  alternative default value will be placed in the type
    375     #  slot.
    376 
    377     def __init__(self, slot_name, user_methods, default_value, **kargs):
    378         InternalMethodSlot.__init__(self, slot_name, **kargs)
    379         self.user_methods = user_methods
    380         self.default_value = default_value
    381 
    382     def slot_code(self, scope):
    383         if scope.defines_any(self.user_methods):
    384             return InternalMethodSlot.slot_code(self, scope)
    385         else:
    386             return self.default_value
    387 
    388 
    389 class TypeFlagsSlot(SlotDescriptor):
    390     #  Descriptor for the type flags slot.
    391 
    392     def slot_code(self, scope):
    393         value = "Py_TPFLAGS_DEFAULT"
    394         if scope.directives['type_version_tag']:
    395             # it's not in 'Py_TPFLAGS_DEFAULT' in Py2
    396             value += "|Py_TPFLAGS_HAVE_VERSION_TAG"
    397         else:
    398             # it's enabled in 'Py_TPFLAGS_DEFAULT' in Py3
    399             value = "(%s&~Py_TPFLAGS_HAVE_VERSION_TAG)" % value
    400         value += "|Py_TPFLAGS_CHECKTYPES|Py_TPFLAGS_HAVE_NEWBUFFER"
    401         if not scope.parent_type.is_final_type:
    402             value += "|Py_TPFLAGS_BASETYPE"
    403         if scope.needs_gc():
    404             value += "|Py_TPFLAGS_HAVE_GC"
    405         return value
    406 
    407 
    408 class DocStringSlot(SlotDescriptor):
    409     #  Descriptor for the docstring slot.
    410 
    411     def slot_code(self, scope):
    412         if scope.doc is not None:
    413             if scope.doc.is_unicode:
    414                 doc = scope.doc.utf8encode()
    415             else:
    416                 doc = scope.doc.byteencode()
    417             return '__Pyx_DOCSTR("%s")' % StringEncoding.escape_byte_string(doc)
    418         else:
    419             return "0"
    420 
    421 
    422 class SuiteSlot(SlotDescriptor):
    423     #  Descriptor for a substructure of the type object.
    424     #
    425     #  sub_slots   [SlotDescriptor]
    426 
    427     def __init__(self, sub_slots, slot_type, slot_name):
    428         SlotDescriptor.__init__(self, slot_name)
    429         self.sub_slots = sub_slots
    430         self.slot_type = slot_type
    431         substructures.append(self)
    432 
    433     def is_empty(self, scope):
    434         for slot in self.sub_slots:
    435             if slot.slot_code(scope) != "0":
    436                 return False
    437         return True
    438 
    439     def substructure_cname(self, scope):
    440         return "%s%s_%s" % (Naming.pyrex_prefix, self.slot_name, scope.class_name)
    441 
    442     def slot_code(self, scope):
    443         if not self.is_empty(scope):
    444             return "&%s" % self.substructure_cname(scope)
    445         return "0"
    446 
    447     def generate_substructure(self, scope, code):
    448         if not self.is_empty(scope):
    449             code.putln("")
    450             code.putln(
    451                 "static %s %s = {" % (
    452                     self.slot_type,
    453                     self.substructure_cname(scope)))
    454             for slot in self.sub_slots:
    455                 slot.generate(scope, code)
    456             code.putln("};")
    457 
    458 substructures = []   # List of all SuiteSlot instances
    459 
    460 class MethodTableSlot(SlotDescriptor):
    461     #  Slot descriptor for the method table.
    462 
    463     def slot_code(self, scope):
    464         if scope.pyfunc_entries:
    465             return scope.method_table_cname
    466         else:
    467             return "0"
    468 
    469 
    470 class MemberTableSlot(SlotDescriptor):
    471     #  Slot descriptor for the table of Python-accessible attributes.
    472 
    473     def slot_code(self, scope):
    474         return "0"
    475 
    476 
    477 class GetSetSlot(SlotDescriptor):
    478     #  Slot descriptor for the table of attribute get & set methods.
    479 
    480     def slot_code(self, scope):
    481         if scope.property_entries:
    482             return scope.getset_table_cname
    483         else:
    484             return "0"
    485 
    486 
    487 class BaseClassSlot(SlotDescriptor):
    488     #  Slot descriptor for the base class slot.
    489 
    490     def __init__(self, name):
    491         SlotDescriptor.__init__(self, name, dynamic = 1)
    492 
    493     def generate_dynamic_init_code(self, scope, code):
    494         base_type = scope.parent_type.base_type
    495         if base_type:
    496             code.putln("%s.%s = %s;" % (
    497                 scope.parent_type.typeobj_cname,
    498                 self.slot_name,
    499                 base_type.typeptr_cname))
    500 
    501 
    502 # The following dictionary maps __xxx__ method names to slot descriptors.
    503 
    504 method_name_to_slot = {}
    505 
    506 ## The following slots are (or could be) initialised with an
    507 ## extern function pointer.
    508 #
    509 #slots_initialised_from_extern = (
    510 #    "tp_free",
    511 #)
    512 
    513 #------------------------------------------------------------------------------------------
    514 #
    515 #  Utility functions for accessing slot table data structures
    516 #
    517 #------------------------------------------------------------------------------------------
    518 
    519 def get_special_method_signature(name):
    520     #  Given a method name, if it is a special method,
    521     #  return its signature, else return None.
    522     slot = method_name_to_slot.get(name)
    523     if slot:
    524         return slot.signature
    525     else:
    526         return None
    527 
    528 
    529 def get_property_accessor_signature(name):
    530     #  Return signature of accessor for an extension type
    531     #  property, else None.
    532     return property_accessor_signatures.get(name)
    533 
    534 
    535 def get_base_slot_function(scope, slot):
    536     #  Returns the function implementing this slot in the baseclass.
    537     #  This is useful for enabling the compiler to optimize calls
    538     #  that recursively climb the class hierarchy.
    539     base_type = scope.parent_type.base_type
    540     if scope.parent_scope is base_type.scope.parent_scope:
    541         parent_slot = slot.slot_code(base_type.scope)
    542         if parent_slot != '0':
    543             entry = scope.parent_scope.lookup_here(scope.parent_type.base_type.name)
    544             if entry.visibility != 'extern':
    545                 return parent_slot
    546     return None
    547 
    548 
    549 def get_slot_function(scope, slot):
    550     #  Returns the function implementing this slot in the baseclass.
    551     #  This is useful for enabling the compiler to optimize calls
    552     #  that recursively climb the class hierarchy.
    553     slot_code = slot.slot_code(scope)
    554     if slot_code != '0':
    555         entry = scope.parent_scope.lookup_here(scope.parent_type.name)
    556         if entry.visibility != 'extern':
    557             return slot_code
    558     return None
    559 
    560 #------------------------------------------------------------------------------------------
    561 #
    562 #  Signatures for generic Python functions and methods.
    563 #
    564 #------------------------------------------------------------------------------------------
    565 
    566 pyfunction_signature = Signature("-*", "O")
    567 pymethod_signature = Signature("T*", "O")
    568 
    569 #------------------------------------------------------------------------------------------
    570 #
    571 #  Signatures for simple Python functions.
    572 #
    573 #------------------------------------------------------------------------------------------
    574 
    575 pyfunction_noargs = Signature("-", "O")
    576 pyfunction_onearg = Signature("-O", "O")
    577 
    578 #------------------------------------------------------------------------------------------
    579 #
    580 #  Signatures for the various kinds of function that
    581 #  can appear in the type object and its substructures.
    582 #
    583 #------------------------------------------------------------------------------------------
    584 
    585 unaryfunc = Signature("T", "O")            # typedef PyObject * (*unaryfunc)(PyObject *);
    586 binaryfunc = Signature("OO", "O")          # typedef PyObject * (*binaryfunc)(PyObject *, PyObject *);
    587 ibinaryfunc = Signature("TO", "O")         # typedef PyObject * (*binaryfunc)(PyObject *, PyObject *);
    588 ternaryfunc = Signature("OOO", "O")        # typedef PyObject * (*ternaryfunc)(PyObject *, PyObject *, PyObject *);
    589 iternaryfunc = Signature("TOO", "O")       # typedef PyObject * (*ternaryfunc)(PyObject *, PyObject *, PyObject *);
    590 callfunc = Signature("T*", "O")            # typedef PyObject * (*ternaryfunc)(PyObject *, PyObject *, PyObject *);
    591 inquiry = Signature("T", "i")              # typedef int (*inquiry)(PyObject *);
    592 lenfunc = Signature("T", "z")              # typedef Py_ssize_t (*lenfunc)(PyObject *);
    593 
    594                                            # typedef int (*coercion)(PyObject **, PyObject **);
    595 intargfunc = Signature("Ti", "O")          # typedef PyObject *(*intargfunc)(PyObject *, int);
    596 ssizeargfunc = Signature("Tz", "O")        # typedef PyObject *(*ssizeargfunc)(PyObject *, Py_ssize_t);
    597 intintargfunc = Signature("Tii", "O")      # typedef PyObject *(*intintargfunc)(PyObject *, int, int);
    598 ssizessizeargfunc = Signature("Tzz", "O")  # typedef PyObject *(*ssizessizeargfunc)(PyObject *, Py_ssize_t, Py_ssize_t);
    599 intobjargproc = Signature("TiO", 'r')      # typedef int(*intobjargproc)(PyObject *, int, PyObject *);
    600 ssizeobjargproc = Signature("TzO", 'r')    # typedef int(*ssizeobjargproc)(PyObject *, Py_ssize_t, PyObject *);
    601 intintobjargproc = Signature("TiiO", 'r')  # typedef int(*intintobjargproc)(PyObject *, int, int, PyObject *);
    602 ssizessizeobjargproc = Signature("TzzO", 'r') # typedef int(*ssizessizeobjargproc)(PyObject *, Py_ssize_t, Py_ssize_t, PyObject *);
    603 
    604 intintargproc = Signature("Tii", 'r')
    605 ssizessizeargproc = Signature("Tzz", 'r')
    606 objargfunc = Signature("TO", "O")
    607 objobjargproc = Signature("TOO", 'r')      # typedef int (*objobjargproc)(PyObject *, PyObject *, PyObject *);
    608 readbufferproc = Signature("TzP", "z")     # typedef Py_ssize_t (*readbufferproc)(PyObject *, Py_ssize_t, void **);
    609 writebufferproc = Signature("TzP", "z")    # typedef Py_ssize_t (*writebufferproc)(PyObject *, Py_ssize_t, void **);
    610 segcountproc = Signature("TZ", "z")        # typedef Py_ssize_t (*segcountproc)(PyObject *, Py_ssize_t *);
    611 charbufferproc = Signature("TzS", "z")     # typedef Py_ssize_t (*charbufferproc)(PyObject *, Py_ssize_t, char **);
    612 objargproc = Signature("TO", 'r')          # typedef int (*objobjproc)(PyObject *, PyObject *);
    613                                            # typedef int (*visitproc)(PyObject *, void *);
    614                                            # typedef int (*traverseproc)(PyObject *, visitproc, void *);
    615 
    616 destructor = Signature("T", "v")           # typedef void (*destructor)(PyObject *);
    617 # printfunc = Signature("TFi", 'r')        # typedef int (*printfunc)(PyObject *, FILE *, int);
    618                                            # typedef PyObject *(*getattrfunc)(PyObject *, char *);
    619 getattrofunc = Signature("TO", "O")        # typedef PyObject *(*getattrofunc)(PyObject *, PyObject *);
    620                                            # typedef int (*setattrfunc)(PyObject *, char *, PyObject *);
    621 setattrofunc = Signature("TOO", 'r')       # typedef int (*setattrofunc)(PyObject *, PyObject *, PyObject *);
    622 delattrofunc = Signature("TO", 'r')
    623 cmpfunc = Signature("TO", "i")             # typedef int (*cmpfunc)(PyObject *, PyObject *);
    624 reprfunc = Signature("T", "O")             # typedef PyObject *(*reprfunc)(PyObject *);
    625 hashfunc = Signature("T", "h")             # typedef Py_hash_t (*hashfunc)(PyObject *);
    626                                            # typedef PyObject *(*richcmpfunc) (PyObject *, PyObject *, int);
    627 richcmpfunc = Signature("OOi", "O")        # typedef PyObject *(*richcmpfunc) (PyObject *, PyObject *, int);
    628 getiterfunc = Signature("T", "O")          # typedef PyObject *(*getiterfunc) (PyObject *);
    629 iternextfunc = Signature("T", "O")         # typedef PyObject *(*iternextfunc) (PyObject *);
    630 descrgetfunc = Signature("TOO", "O")       # typedef PyObject *(*descrgetfunc) (PyObject *, PyObject *, PyObject *);
    631 descrsetfunc = Signature("TOO", 'r')       # typedef int (*descrsetfunc) (PyObject *, PyObject *, PyObject *);
    632 descrdelfunc = Signature("TO", 'r')
    633 initproc = Signature("T*", 'r')            # typedef int (*initproc)(PyObject *, PyObject *, PyObject *);
    634                                            # typedef PyObject *(*newfunc)(struct _typeobject *, PyObject *, PyObject *);
    635                                            # typedef PyObject *(*allocfunc)(struct _typeobject *, int);
    636 
    637 getbufferproc = Signature("TBi", "r")      # typedef int (*getbufferproc)(PyObject *, Py_buffer *, int);
    638 releasebufferproc = Signature("TB", "v")   # typedef void (*releasebufferproc)(PyObject *, Py_buffer *);
    639 
    640 
    641 #------------------------------------------------------------------------------------------
    642 #
    643 #  Signatures for accessor methods of properties.
    644 #
    645 #------------------------------------------------------------------------------------------
    646 
    647 property_accessor_signatures = {
    648     '__get__': Signature("T", "O"),
    649     '__set__': Signature("TO", 'r'),
    650     '__del__': Signature("T", 'r')
    651 }
    652 
    653 #------------------------------------------------------------------------------------------
    654 #
    655 #  Descriptor tables for the slots of the various type object
    656 #  substructures, in the order they appear in the structure.
    657 #
    658 #------------------------------------------------------------------------------------------
    659 
    660 PyNumberMethods = (
    661     MethodSlot(binaryfunc, "nb_add", "__add__"),
    662     MethodSlot(binaryfunc, "nb_subtract", "__sub__"),
    663     MethodSlot(binaryfunc, "nb_multiply", "__mul__"),
    664     MethodSlot(binaryfunc, "nb_divide", "__div__", py3 = False),
    665     MethodSlot(binaryfunc, "nb_remainder", "__mod__"),
    666     MethodSlot(binaryfunc, "nb_divmod", "__divmod__"),
    667     MethodSlot(ternaryfunc, "nb_power", "__pow__"),
    668     MethodSlot(unaryfunc, "nb_negative", "__neg__"),
    669     MethodSlot(unaryfunc, "nb_positive", "__pos__"),
    670     MethodSlot(unaryfunc, "nb_absolute", "__abs__"),
    671     MethodSlot(inquiry, "nb_nonzero", "__nonzero__", py3 = ("nb_bool", "__bool__")),
    672     MethodSlot(unaryfunc, "nb_invert", "__invert__"),
    673     MethodSlot(binaryfunc, "nb_lshift", "__lshift__"),
    674     MethodSlot(binaryfunc, "nb_rshift", "__rshift__"),
    675     MethodSlot(binaryfunc, "nb_and", "__and__"),
    676     MethodSlot(binaryfunc, "nb_xor", "__xor__"),
    677     MethodSlot(binaryfunc, "nb_or", "__or__"),
    678     EmptySlot("nb_coerce", py3 = False),
    679     MethodSlot(unaryfunc, "nb_int", "__int__", fallback="__long__"),
    680     MethodSlot(unaryfunc, "nb_long", "__long__", fallback="__int__", py3 = "<RESERVED>"),
    681     MethodSlot(unaryfunc, "nb_float", "__float__"),
    682     MethodSlot(unaryfunc, "nb_oct", "__oct__", py3 = False),
    683     MethodSlot(unaryfunc, "nb_hex", "__hex__", py3 = False),
    684 
    685     # Added in release 2.0
    686     MethodSlot(ibinaryfunc, "nb_inplace_add", "__iadd__"),
    687     MethodSlot(ibinaryfunc, "nb_inplace_subtract", "__isub__"),
    688     MethodSlot(ibinaryfunc, "nb_inplace_multiply", "__imul__"),
    689     MethodSlot(ibinaryfunc, "nb_inplace_divide", "__idiv__", py3 = False),
    690     MethodSlot(ibinaryfunc, "nb_inplace_remainder", "__imod__"),
    691     MethodSlot(ibinaryfunc, "nb_inplace_power", "__ipow__"), # actually ternaryfunc!!!
    692     MethodSlot(ibinaryfunc, "nb_inplace_lshift", "__ilshift__"),
    693     MethodSlot(ibinaryfunc, "nb_inplace_rshift", "__irshift__"),
    694     MethodSlot(ibinaryfunc, "nb_inplace_and", "__iand__"),
    695     MethodSlot(ibinaryfunc, "nb_inplace_xor", "__ixor__"),
    696     MethodSlot(ibinaryfunc, "nb_inplace_or", "__ior__"),
    697 
    698     # Added in release 2.2
    699     # The following require the Py_TPFLAGS_HAVE_CLASS flag
    700     MethodSlot(binaryfunc, "nb_floor_divide", "__floordiv__"),
    701     MethodSlot(binaryfunc, "nb_true_divide", "__truediv__"),
    702     MethodSlot(ibinaryfunc, "nb_inplace_floor_divide", "__ifloordiv__"),
    703     MethodSlot(ibinaryfunc, "nb_inplace_true_divide", "__itruediv__"),
    704 
    705     # Added in release 2.5
    706     MethodSlot(unaryfunc, "nb_index", "__index__", ifdef = "PY_VERSION_HEX >= 0x02050000")
    707 )
    708 
    709 PySequenceMethods = (
    710     MethodSlot(lenfunc, "sq_length", "__len__"),
    711     EmptySlot("sq_concat"), # nb_add used instead
    712     EmptySlot("sq_repeat"), # nb_multiply used instead
    713     SyntheticSlot("sq_item", ["__getitem__"], "0"),    #EmptySlot("sq_item"),   # mp_subscript used instead
    714     MethodSlot(ssizessizeargfunc, "sq_slice", "__getslice__"),
    715     EmptySlot("sq_ass_item"), # mp_ass_subscript used instead
    716     SyntheticSlot("sq_ass_slice", ["__setslice__", "__delslice__"], "0"),
    717     MethodSlot(cmpfunc, "sq_contains", "__contains__"),
    718     EmptySlot("sq_inplace_concat"), # nb_inplace_add used instead
    719     EmptySlot("sq_inplace_repeat"), # nb_inplace_multiply used instead
    720 )
    721 
    722 PyMappingMethods = (
    723     MethodSlot(lenfunc, "mp_length", "__len__"),
    724     MethodSlot(objargfunc, "mp_subscript", "__getitem__"),
    725     SyntheticSlot("mp_ass_subscript", ["__setitem__", "__delitem__"], "0"),
    726 )
    727 
    728 PyBufferProcs = (
    729     MethodSlot(readbufferproc, "bf_getreadbuffer", "__getreadbuffer__", py3 = False),
    730     MethodSlot(writebufferproc, "bf_getwritebuffer", "__getwritebuffer__", py3 = False),
    731     MethodSlot(segcountproc, "bf_getsegcount", "__getsegcount__", py3 = False),
    732     MethodSlot(charbufferproc, "bf_getcharbuffer", "__getcharbuffer__", py3 = False),
    733 
    734     MethodSlot(getbufferproc, "bf_getbuffer", "__getbuffer__", ifdef = "PY_VERSION_HEX >= 0x02060000"),
    735     MethodSlot(releasebufferproc, "bf_releasebuffer", "__releasebuffer__", ifdef = "PY_VERSION_HEX >= 0x02060000")
    736 )
    737 
    738 #------------------------------------------------------------------------------------------
    739 #
    740 #  The main slot table. This table contains descriptors for all the
    741 #  top-level type slots, beginning with tp_dealloc, in the order they
    742 #  appear in the type object.
    743 #
    744 #------------------------------------------------------------------------------------------
    745 
    746 slot_table = (
    747     ConstructorSlot("tp_dealloc", '__dealloc__'),
    748     EmptySlot("tp_print"), #MethodSlot(printfunc, "tp_print", "__print__"),
    749     EmptySlot("tp_getattr"),
    750     EmptySlot("tp_setattr"),
    751     MethodSlot(cmpfunc, "tp_compare", "__cmp__", py3 = '<RESERVED>'),
    752     MethodSlot(reprfunc, "tp_repr", "__repr__"),
    753 
    754     SuiteSlot(PyNumberMethods, "PyNumberMethods", "tp_as_number"),
    755     SuiteSlot(PySequenceMethods, "PySequenceMethods", "tp_as_sequence"),
    756     SuiteSlot(PyMappingMethods, "PyMappingMethods", "tp_as_mapping"),
    757 
    758     MethodSlot(hashfunc, "tp_hash", "__hash__", inherited=False),    # Py3 checks for __richcmp__
    759     MethodSlot(callfunc, "tp_call", "__call__"),
    760     MethodSlot(reprfunc, "tp_str", "__str__"),
    761 
    762     SyntheticSlot("tp_getattro", ["__getattr__","__getattribute__"], "0"), #"PyObject_GenericGetAttr"),
    763     SyntheticSlot("tp_setattro", ["__setattr__", "__delattr__"], "0"), #"PyObject_GenericSetAttr"),
    764 
    765     SuiteSlot(PyBufferProcs, "PyBufferProcs", "tp_as_buffer"),
    766 
    767     TypeFlagsSlot("tp_flags"),
    768     DocStringSlot("tp_doc"),
    769 
    770     GCDependentSlot("tp_traverse"),
    771     GCClearReferencesSlot("tp_clear"),
    772 
    773     # Later -- synthesize a method to split into separate ops?
    774     MethodSlot(richcmpfunc, "tp_richcompare", "__richcmp__", inherited=False),  # Py3 checks for __hash__
    775 
    776     EmptySlot("tp_weaklistoffset"),
    777 
    778     MethodSlot(getiterfunc, "tp_iter", "__iter__"),
    779     MethodSlot(iternextfunc, "tp_iternext", "__next__"),
    780 
    781     MethodTableSlot("tp_methods"),
    782     MemberTableSlot("tp_members"),
    783     GetSetSlot("tp_getset"),
    784 
    785     BaseClassSlot("tp_base"), #EmptySlot("tp_base"),
    786     EmptySlot("tp_dict"),
    787 
    788     SyntheticSlot("tp_descr_get", ["__get__"], "0"),
    789     SyntheticSlot("tp_descr_set", ["__set__", "__delete__"], "0"),
    790 
    791     EmptySlot("tp_dictoffset"),
    792 
    793     MethodSlot(initproc, "tp_init", "__init__"),
    794     EmptySlot("tp_alloc"), #FixedSlot("tp_alloc", "PyType_GenericAlloc"),
    795     InternalMethodSlot("tp_new"),
    796     EmptySlot("tp_free"),
    797 
    798     EmptySlot("tp_is_gc"),
    799     EmptySlot("tp_bases"),
    800     EmptySlot("tp_mro"),
    801     EmptySlot("tp_cache"),
    802     EmptySlot("tp_subclasses"),
    803     EmptySlot("tp_weaklist"),
    804     EmptySlot("tp_del"),
    805     EmptySlot("tp_version_tag", ifdef="PY_VERSION_HEX >= 0x02060000"),
    806     EmptySlot("tp_finalize", ifdef="PY_VERSION_HEX >= 0x030400a1"),
    807 )
    808 
    809 #------------------------------------------------------------------------------------------
    810 #
    811 #  Descriptors for special methods which don't appear directly
    812 #  in the type object or its substructures. These methods are
    813 #  called from slot functions synthesized by Cython.
    814 #
    815 #------------------------------------------------------------------------------------------
    816 
    817 MethodSlot(initproc, "", "__cinit__")
    818 MethodSlot(destructor, "", "__dealloc__")
    819 MethodSlot(objobjargproc, "", "__setitem__")
    820 MethodSlot(objargproc, "", "__delitem__")
    821 MethodSlot(ssizessizeobjargproc, "", "__setslice__")
    822 MethodSlot(ssizessizeargproc, "", "__delslice__")
    823 MethodSlot(getattrofunc, "", "__getattr__")
    824 MethodSlot(setattrofunc, "", "__setattr__")
    825 MethodSlot(delattrofunc, "", "__delattr__")
    826 MethodSlot(descrgetfunc, "", "__get__")
    827 MethodSlot(descrsetfunc, "", "__set__")
    828 MethodSlot(descrdelfunc, "", "__delete__")
    829 
    830 
    831 # Method flags for python-exposed methods.
    832 
    833 method_noargs   = "METH_NOARGS"
    834 method_onearg   = "METH_O"
    835 method_varargs  = "METH_VARARGS"
    836 method_keywords = "METH_KEYWORDS"
    837 method_coexist  = "METH_COEXIST"
    838