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