• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1#
2#   Tables describing slots in the CPython type object
3#   and associated know-how.
4#
5
6import Naming
7import PyrexTypes
8import StringEncoding
9
10invisible = ['__cinit__', '__dealloc__', '__richcmp__',
11             '__nonzero__', '__bool__']
12
13class 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
161class 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
246class 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
259class 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
266class 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
302class 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
315class 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
337class 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
345class 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
369class 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
389class 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
408class 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
422class 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
458substructures = []   # List of all SuiteSlot instances
459
460class 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
470class MemberTableSlot(SlotDescriptor):
471    #  Slot descriptor for the table of Python-accessible attributes.
472
473    def slot_code(self, scope):
474        return "0"
475
476
477class 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
487class 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
504method_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
519def 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
529def 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
535def 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
549def 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
566pyfunction_signature = Signature("-*", "O")
567pymethod_signature = Signature("T*", "O")
568
569#------------------------------------------------------------------------------------------
570#
571#  Signatures for simple Python functions.
572#
573#------------------------------------------------------------------------------------------
574
575pyfunction_noargs = Signature("-", "O")
576pyfunction_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
585unaryfunc = Signature("T", "O")            # typedef PyObject * (*unaryfunc)(PyObject *);
586binaryfunc = Signature("OO", "O")          # typedef PyObject * (*binaryfunc)(PyObject *, PyObject *);
587ibinaryfunc = Signature("TO", "O")         # typedef PyObject * (*binaryfunc)(PyObject *, PyObject *);
588ternaryfunc = Signature("OOO", "O")        # typedef PyObject * (*ternaryfunc)(PyObject *, PyObject *, PyObject *);
589iternaryfunc = Signature("TOO", "O")       # typedef PyObject * (*ternaryfunc)(PyObject *, PyObject *, PyObject *);
590callfunc = Signature("T*", "O")            # typedef PyObject * (*ternaryfunc)(PyObject *, PyObject *, PyObject *);
591inquiry = Signature("T", "i")              # typedef int (*inquiry)(PyObject *);
592lenfunc = Signature("T", "z")              # typedef Py_ssize_t (*lenfunc)(PyObject *);
593
594                                           # typedef int (*coercion)(PyObject **, PyObject **);
595intargfunc = Signature("Ti", "O")          # typedef PyObject *(*intargfunc)(PyObject *, int);
596ssizeargfunc = Signature("Tz", "O")        # typedef PyObject *(*ssizeargfunc)(PyObject *, Py_ssize_t);
597intintargfunc = Signature("Tii", "O")      # typedef PyObject *(*intintargfunc)(PyObject *, int, int);
598ssizessizeargfunc = Signature("Tzz", "O")  # typedef PyObject *(*ssizessizeargfunc)(PyObject *, Py_ssize_t, Py_ssize_t);
599intobjargproc = Signature("TiO", 'r')      # typedef int(*intobjargproc)(PyObject *, int, PyObject *);
600ssizeobjargproc = Signature("TzO", 'r')    # typedef int(*ssizeobjargproc)(PyObject *, Py_ssize_t, PyObject *);
601intintobjargproc = Signature("TiiO", 'r')  # typedef int(*intintobjargproc)(PyObject *, int, int, PyObject *);
602ssizessizeobjargproc = Signature("TzzO", 'r') # typedef int(*ssizessizeobjargproc)(PyObject *, Py_ssize_t, Py_ssize_t, PyObject *);
603
604intintargproc = Signature("Tii", 'r')
605ssizessizeargproc = Signature("Tzz", 'r')
606objargfunc = Signature("TO", "O")
607objobjargproc = Signature("TOO", 'r')      # typedef int (*objobjargproc)(PyObject *, PyObject *, PyObject *);
608readbufferproc = Signature("TzP", "z")     # typedef Py_ssize_t (*readbufferproc)(PyObject *, Py_ssize_t, void **);
609writebufferproc = Signature("TzP", "z")    # typedef Py_ssize_t (*writebufferproc)(PyObject *, Py_ssize_t, void **);
610segcountproc = Signature("TZ", "z")        # typedef Py_ssize_t (*segcountproc)(PyObject *, Py_ssize_t *);
611charbufferproc = Signature("TzS", "z")     # typedef Py_ssize_t (*charbufferproc)(PyObject *, Py_ssize_t, char **);
612objargproc = Signature("TO", 'r')          # typedef int (*objobjproc)(PyObject *, PyObject *);
613                                           # typedef int (*visitproc)(PyObject *, void *);
614                                           # typedef int (*traverseproc)(PyObject *, visitproc, void *);
615
616destructor = Signature("T", "v")           # typedef void (*destructor)(PyObject *);
617# printfunc = Signature("TFi", 'r')        # typedef int (*printfunc)(PyObject *, FILE *, int);
618                                           # typedef PyObject *(*getattrfunc)(PyObject *, char *);
619getattrofunc = Signature("TO", "O")        # typedef PyObject *(*getattrofunc)(PyObject *, PyObject *);
620                                           # typedef int (*setattrfunc)(PyObject *, char *, PyObject *);
621setattrofunc = Signature("TOO", 'r')       # typedef int (*setattrofunc)(PyObject *, PyObject *, PyObject *);
622delattrofunc = Signature("TO", 'r')
623cmpfunc = Signature("TO", "i")             # typedef int (*cmpfunc)(PyObject *, PyObject *);
624reprfunc = Signature("T", "O")             # typedef PyObject *(*reprfunc)(PyObject *);
625hashfunc = Signature("T", "h")             # typedef Py_hash_t (*hashfunc)(PyObject *);
626                                           # typedef PyObject *(*richcmpfunc) (PyObject *, PyObject *, int);
627richcmpfunc = Signature("OOi", "O")        # typedef PyObject *(*richcmpfunc) (PyObject *, PyObject *, int);
628getiterfunc = Signature("T", "O")          # typedef PyObject *(*getiterfunc) (PyObject *);
629iternextfunc = Signature("T", "O")         # typedef PyObject *(*iternextfunc) (PyObject *);
630descrgetfunc = Signature("TOO", "O")       # typedef PyObject *(*descrgetfunc) (PyObject *, PyObject *, PyObject *);
631descrsetfunc = Signature("TOO", 'r')       # typedef int (*descrsetfunc) (PyObject *, PyObject *, PyObject *);
632descrdelfunc = Signature("TO", 'r')
633initproc = 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
637getbufferproc = Signature("TBi", "r")      # typedef int (*getbufferproc)(PyObject *, Py_buffer *, int);
638releasebufferproc = Signature("TB", "v")   # typedef void (*releasebufferproc)(PyObject *, Py_buffer *);
639
640
641#------------------------------------------------------------------------------------------
642#
643#  Signatures for accessor methods of properties.
644#
645#------------------------------------------------------------------------------------------
646
647property_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
660PyNumberMethods = (
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
709PySequenceMethods = (
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
722PyMappingMethods = (
723    MethodSlot(lenfunc, "mp_length", "__len__"),
724    MethodSlot(objargfunc, "mp_subscript", "__getitem__"),
725    SyntheticSlot("mp_ass_subscript", ["__setitem__", "__delitem__"], "0"),
726)
727
728PyBufferProcs = (
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
746slot_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
817MethodSlot(initproc, "", "__cinit__")
818MethodSlot(destructor, "", "__dealloc__")
819MethodSlot(objobjargproc, "", "__setitem__")
820MethodSlot(objargproc, "", "__delitem__")
821MethodSlot(ssizessizeobjargproc, "", "__setslice__")
822MethodSlot(ssizessizeargproc, "", "__delslice__")
823MethodSlot(getattrofunc, "", "__getattr__")
824MethodSlot(setattrofunc, "", "__setattr__")
825MethodSlot(delattrofunc, "", "__delattr__")
826MethodSlot(descrgetfunc, "", "__get__")
827MethodSlot(descrsetfunc, "", "__set__")
828MethodSlot(descrdelfunc, "", "__delete__")
829
830
831# Method flags for python-exposed methods.
832
833method_noargs   = "METH_NOARGS"
834method_onearg   = "METH_O"
835method_varargs  = "METH_VARARGS"
836method_keywords = "METH_KEYWORDS"
837method_coexist  = "METH_COEXIST"
838