cython

Форк
0
/
TypeSlots.py 
1179 строк · 48.7 Кб
1
#
2
#   Tables describing slots in the CPython type object
3
#   and associated know-how.
4
#
5

6

7
from . import Naming
8
from . import PyrexTypes
9
from .Errors import error, warn_once
10

11
import copy
12

13
invisible = ['__cinit__', '__dealloc__', '__richcmp__',
14
             '__nonzero__', '__bool__']
15

16
richcmp_special_methods = ['__eq__', '__ne__', '__lt__', '__gt__', '__le__', '__ge__']
17

18

19
class Signature:
20
    #  Method slot signature descriptor.
21
    #
22
    #  has_dummy_arg      boolean
23
    #  has_generic_args   boolean
24
    #  fixed_arg_format   string
25
    #  ret_format         string
26
    #  error_value        string
27
    #  use_fastcall       boolean
28
    #
29
    #  The formats are strings made up of the following
30
    #  characters:
31
    #
32
    #    'O'  Python object
33
    #    'T'  Python object of the type of 'self'
34
    #    'v'  void
35
    #    'p'  void *
36
    #    'P'  void **
37
    #    'i'  int
38
    #    'b'  bint
39
    #    'I'  int *
40
    #    'l'  long
41
    #    'f'  float
42
    #    'd'  double
43
    #    'h'  Py_hash_t
44
    #    'z'  Py_ssize_t
45
    #    'Z'  Py_ssize_t *
46
    #    's'  char *
47
    #    'S'  char **
48
    #    'r'  int used only to signal exception
49
    #    'B'  Py_buffer *
50
    #    '-'  dummy 'self' argument (not used)
51
    #    '*'  rest of args passed as generic Python
52
    #           arg tuple and kw dict (must be last
53
    #           char in format string)
54
    #    '?'  optional object arg (currently for pow only)
55

56
    format_map = {
57
        'O': PyrexTypes.py_object_type,
58
        'v': PyrexTypes.c_void_type,
59
        'p': PyrexTypes.c_void_ptr_type,
60
        'P': PyrexTypes.c_void_ptr_ptr_type,
61
        'i': PyrexTypes.c_int_type,
62
        'b': PyrexTypes.c_bint_type,
63
        'I': PyrexTypes.c_int_ptr_type,
64
        'l': PyrexTypes.c_long_type,
65
        'f': PyrexTypes.c_float_type,
66
        'd': PyrexTypes.c_double_type,
67
        'h': PyrexTypes.c_py_hash_t_type,
68
        'z': PyrexTypes.c_py_ssize_t_type,
69
        'Z': PyrexTypes.c_py_ssize_t_ptr_type,
70
        's': PyrexTypes.c_char_ptr_type,
71
        'S': PyrexTypes.c_char_ptr_ptr_type,
72
        'r': PyrexTypes.c_returncode_type,
73
        'B': PyrexTypes.c_py_buffer_ptr_type,
74
        '?': PyrexTypes.py_object_type
75
        # 'T', '-' and '*' are handled otherwise
76
        # and are not looked up in here
77
    }
78

79
    type_to_format_map = {type_: format_ for format_, type_ in format_map.items()}
80

81
    error_value_map = {
82
        'O': "NULL",
83
        'T': "NULL",
84
        'i': "-1",
85
        'b': "-1",
86
        'l': "-1",
87
        'r': "-1",
88
        'h': "-1",
89
        'z': "-1",
90
    }
91

92
    # Use METH_FASTCALL instead of METH_VARARGS
93
    use_fastcall = False
94

95
    def __init__(self, arg_format, ret_format, nogil=False):
96
        self.has_dummy_arg = False
97
        self.has_generic_args = False
98
        self.optional_object_arg_count = 0
99
        if arg_format[:1] == '-':
100
            self.has_dummy_arg = True
101
            arg_format = arg_format[1:]
102
        if arg_format[-1:] == '*':
103
            self.has_generic_args = True
104
            arg_format = arg_format[:-1]
105
        if arg_format[-1:] == '?':
106
            self.optional_object_arg_count += 1
107
        self.fixed_arg_format = arg_format
108
        self.ret_format = ret_format
109
        self.error_value = self.error_value_map.get(ret_format, None)
110
        self.exception_check = ret_format != 'r' and self.error_value is not None
111
        self.is_staticmethod = False
112
        self.nogil = nogil
113

114
    def __repr__(self):
115
        return '<Signature[%s(%s%s)]>' % (
116
            self.ret_format,
117
            ', '.join(self.fixed_arg_format),
118
            '*' if self.has_generic_args else '')
119

120
    def min_num_fixed_args(self):
121
        return self.max_num_fixed_args() - self.optional_object_arg_count
122

123
    def max_num_fixed_args(self):
124
        return len(self.fixed_arg_format)
125

126
    def is_self_arg(self, i):
127
        # argument is 'self' for methods or 'class' for classmethods
128
        return self.fixed_arg_format[i] == 'T'
129

130
    def returns_self_type(self):
131
        # return type is same as 'self' argument type
132
        return self.ret_format == 'T'
133

134
    def fixed_arg_type(self, i):
135
        return self.format_map[self.fixed_arg_format[i]]
136

137
    def return_type(self):
138
        return self.format_map[self.ret_format]
139

140
    def format_from_type(self, arg_type):
141
        if arg_type.is_pyobject:
142
            arg_type = PyrexTypes.py_object_type
143
        return self.type_to_format_map[arg_type]
144

145
    def exception_value(self):
146
        return self.error_value_map.get(self.ret_format)
147

148
    def function_type(self, self_arg_override=None):
149
        #  Construct a C function type descriptor for this signature
150
        args = []
151
        for i in range(self.max_num_fixed_args()):
152
            if self_arg_override is not None and self.is_self_arg(i):
153
                assert isinstance(self_arg_override, PyrexTypes.CFuncTypeArg)
154
                args.append(self_arg_override)
155
            else:
156
                arg_type = self.fixed_arg_type(i)
157
                args.append(PyrexTypes.CFuncTypeArg("", arg_type, None))
158
        if self_arg_override is not None and self.returns_self_type():
159
            ret_type = self_arg_override.type
160
        else:
161
            ret_type = self.return_type()
162
        exc_value = self.exception_value()
163
        return PyrexTypes.CFuncType(
164
            ret_type, args, exception_value=exc_value,
165
            exception_check=self.exception_check,
166
            nogil=self.nogil)
167

168
    def method_flags(self):
169
        if self.ret_format == "O":
170
            full_args = self.fixed_arg_format
171
            if self.has_dummy_arg:
172
                full_args = "O" + full_args
173
            if full_args in ["O", "T"]:
174
                if not self.has_generic_args:
175
                    return [method_noargs]
176
                elif self.use_fastcall:
177
                    return [method_fastcall, method_keywords]
178
                else:
179
                    return [method_varargs, method_keywords]
180
            elif full_args in ["OO", "TO"] and not self.has_generic_args:
181
                return [method_onearg]
182

183
            if self.is_staticmethod:
184
                if self.use_fastcall:
185
                    return [method_fastcall, method_keywords]
186
                else:
187
                    return [method_varargs, method_keywords]
188
        return None
189

190
    def method_function_type(self):
191
        # Return the C function type
192
        mflags = self.method_flags()
193
        kw = "WithKeywords" if (method_keywords in mflags) else ""
194
        for m in mflags:
195
            if m == method_noargs or m == method_onearg:
196
                return "PyCFunction"
197
            if m == method_varargs:
198
                return "PyCFunction" + kw
199
            if m == method_fastcall:
200
                return "__Pyx_PyCFunction_FastCall" + kw
201
        return None
202

203
    def with_fastcall(self):
204
        # Return a copy of this Signature with use_fastcall=True
205
        sig = copy.copy(self)
206
        sig.use_fastcall = True
207
        return sig
208

209
    @property
210
    def fastvar(self):
211
        # Used to select variants of functions, one dealing with METH_VARARGS
212
        # and one dealing with __Pyx_METH_FASTCALL
213
        if self.use_fastcall:
214
            return "FASTCALL"
215
        else:
216
            return "VARARGS"
217

218

219
class SlotDescriptor:
220
    #  Abstract base class for type slot descriptors.
221
    #
222
    #  slot_name    string           Member name of the slot in the type object
223
    #  is_initialised_dynamically    Is initialised by code in the module init function
224
    #  is_inherited                  Is inherited by subtypes (see PyType_Ready())
225
    #  ifdef                         Full #ifdef string that slot is wrapped in. Using this causes flags to be ignored.
226
    #  used_ifdef                    Full #ifdef string that the slot value is wrapped in (otherwise it is assigned NULL)
227
    #                                Unlike "ifdef" the slot is defined and this just controls if it receives a value
228

229
    def __init__(self, slot_name, dynamic=False, inherited=False,
230
                 ifdef=None, is_binop=False,
231
                 used_ifdef=None):
232
        self.slot_name = slot_name
233
        self.is_initialised_dynamically = dynamic
234
        self.is_inherited = inherited
235
        self.ifdef = ifdef
236
        self.used_ifdef = used_ifdef
237
        self.is_binop = is_binop
238

239
    def slot_code(self, scope):
240
        raise NotImplementedError()
241

242
    def spec_value(self, scope):
243
        return self.slot_code(scope)
244

245
    def preprocessor_guard_code(self):
246
        ifdef = self.ifdef
247
        guard = None
248
        if ifdef:
249
            guard = "#if %s" % ifdef
250
        return guard
251

252
    def generate_spec(self, scope, code):
253
        if self.is_initialised_dynamically:
254
            return
255
        value = self.spec_value(scope)
256
        if value == "0":
257
            return
258
        preprocessor_guard = self.preprocessor_guard_code()
259
        if not preprocessor_guard:
260
            if self.slot_name.startswith(('bf_', 'am_')):
261
                # The buffer protocol requires Limited API 3.11 and 'am_send' requires 3.10,
262
                # so check if the spec slots are available.
263
                preprocessor_guard = "#if defined(Py_%s)" % self.slot_name
264
        if preprocessor_guard:
265
            code.putln(preprocessor_guard)
266
        if self.used_ifdef:
267
            # different from preprocessor guard - this defines if we *want* to define it,
268
            # rather than if the slot exists
269
            code.putln(f"#if {self.used_ifdef}")
270
        code.putln("{Py_%s, (void *)%s}," % (self.slot_name, value))
271
        if self.used_ifdef:
272
            code.putln("#endif")
273
        if preprocessor_guard:
274
            code.putln("#endif")
275

276
    def generate(self, scope, code):
277
        preprocessor_guard = self.preprocessor_guard_code()
278
        if preprocessor_guard:
279
            code.putln(preprocessor_guard)
280

281
        end_pypy_guard = False
282
        if self.is_initialised_dynamically:
283
            value = "0"
284
        else:
285
            value = self.slot_code(scope)
286
            if value == "0" and self.is_inherited:
287
                # PyPy currently has a broken PyType_Ready() that fails to
288
                # inherit some slots.  To work around this, we explicitly
289
                # set inherited slots here, but only in PyPy since CPython
290
                # handles this better than we do (except for buffer slots in type specs).
291
                inherited_value = value
292
                current_scope = scope
293
                while (inherited_value == "0"
294
                       and current_scope.parent_type
295
                       and current_scope.parent_type.base_type
296
                       and current_scope.parent_type.base_type.scope):
297
                    current_scope = current_scope.parent_type.base_type.scope
298
                    inherited_value = self.slot_code(current_scope)
299
                if inherited_value != "0":
300
                    # we always need inherited buffer slots for the type spec
301
                    is_buffer_slot = int(self.slot_name in ("bf_getbuffer", "bf_releasebuffer"))
302
                    code.putln("#if CYTHON_COMPILING_IN_PYPY || %d" % is_buffer_slot)
303
                    code.putln("%s, /*%s*/" % (inherited_value, self.slot_name))
304
                    code.putln("#else")
305
                    end_pypy_guard = True
306

307
        if self.used_ifdef:
308
            code.putln("#if %s" % self.used_ifdef)
309
        code.putln("%s, /*%s*/" % (value, self.slot_name))
310
        if self.used_ifdef:
311
            code.putln("#else")
312
            code.putln("NULL, /*%s*/" % self.slot_name)
313
            code.putln("#endif")
314

315
        if end_pypy_guard:
316
            code.putln("#endif")
317

318
        if preprocessor_guard:
319
            code.putln("#endif")
320

321
    # Some C implementations have trouble statically
322
    # initialising a global with a pointer to an extern
323
    # function, so we initialise some of the type slots
324
    # in the module init function instead.
325

326
    def generate_dynamic_init_code(self, scope, code):
327
        if self.is_initialised_dynamically:
328
            self.generate_set_slot_code(
329
                self.slot_code(scope), scope, code)
330

331
    def generate_set_slot_code(self, value, scope, code):
332
        if value == "0":
333
            return
334

335
        if scope.parent_type.typeptr_cname:
336
            target = "%s->%s" % (scope.parent_type.typeptr_cname, self.slot_name)
337
        else:
338
            assert scope.parent_type.typeobj_cname
339
            target = "%s.%s" % (scope.parent_type.typeobj_cname, self.slot_name)
340

341
        code.putln("%s = %s;" % (target, value))
342

343

344
class FixedSlot(SlotDescriptor):
345
    #  Descriptor for a type slot with a fixed value.
346
    #
347
    #  value        string
348

349
    def __init__(self, slot_name, value, ifdef=None):
350
        SlotDescriptor.__init__(self, slot_name, ifdef=ifdef)
351
        self.value = value
352

353
    def slot_code(self, scope):
354
        return self.value
355

356

357
class EmptySlot(FixedSlot):
358
    #  Descriptor for a type slot whose value is always 0.
359

360
    def __init__(self, slot_name, ifdef=None):
361
        FixedSlot.__init__(self, slot_name, "0", ifdef=ifdef)
362

363

364
class MethodSlot(SlotDescriptor):
365
    #  Type slot descriptor for a user-definable method.
366
    #
367
    #  signature    Signature
368
    #  method_name  string           The __xxx__ name of the method
369
    #  alternatives [string]         Alternative list of __xxx__ names for the method
370

371
    def __init__(self, signature, slot_name, method_name, method_name_to_slot,
372
                 fallback=None, ifdef=None, inherited=True):
373
        SlotDescriptor.__init__(self, slot_name,
374
                                ifdef=ifdef, inherited=inherited)
375
        self.signature = signature
376
        self.slot_name = slot_name
377
        self.method_name = method_name
378
        self.alternatives = []
379
        method_name_to_slot[method_name] = self
380
        #
381
        if fallback:
382
            self.alternatives.append(fallback)
383

384
    def slot_code(self, scope):
385
        entry = scope.lookup_here(self.method_name)
386
        if entry and entry.is_special and entry.func_cname:
387
            for method_name in self.alternatives:
388
                alt_entry = scope.lookup_here(method_name)
389
                if alt_entry:
390
                    warn_once(alt_entry.pos,
391
                              f"{method_name} was removed in Python 3; ignoring it and using {self.method_name} instead",
392
                              2)
393
            return entry.func_cname
394
        for method_name in self.alternatives:
395
            entry = scope.lookup_here(method_name)
396
            if entry and entry.is_special and entry.func_cname:
397
                warn_once(entry.pos,
398
                          f"{method_name} was removed in Python 3; use {self.method_name} instead",
399
                          2)
400
                return entry.func_cname
401
        return "0"
402

403

404
class InternalMethodSlot(SlotDescriptor):
405
    #  Type slot descriptor for a method which is always
406
    #  synthesized by Cython.
407
    #
408
    #  slot_name    string           Member name of the slot in the type object
409

410
    def __init__(self, slot_name, **kargs):
411
        SlotDescriptor.__init__(self, slot_name, **kargs)
412

413
    def slot_code(self, scope):
414
        return scope.mangle_internal(self.slot_name)
415

416

417
class GCDependentSlot(InternalMethodSlot):
418
    #  Descriptor for a slot whose value depends on whether
419
    #  the type participates in GC.
420

421
    def __init__(self, slot_name, **kargs):
422
        InternalMethodSlot.__init__(self, slot_name, **kargs)
423

424
    def slot_code(self, scope):
425
        if not scope.needs_gc():
426
            return "0"
427
        if not scope.has_cyclic_pyobject_attrs:
428
            # if the type does not have GC relevant object attributes, it can
429
            # delegate GC methods to its parent - iff the parent functions
430
            # are defined in the same module
431
            parent_type_scope = scope.parent_type.base_type.scope
432
            if scope.parent_scope is parent_type_scope.parent_scope:
433
                entry = scope.parent_scope.lookup_here(scope.parent_type.base_type.name)
434
                if entry.visibility != 'extern':
435
                    return self.slot_code(parent_type_scope)
436
        return InternalMethodSlot.slot_code(self, scope)
437

438

439
class GCClearReferencesSlot(GCDependentSlot):
440

441
    def slot_code(self, scope):
442
        if scope.needs_tp_clear():
443
            return GCDependentSlot.slot_code(self, scope)
444
        return "0"
445

446

447
class ConstructorSlot(InternalMethodSlot):
448
    #  Descriptor for tp_new and tp_dealloc.
449

450
    def __init__(self, slot_name, method=None, **kargs):
451
        InternalMethodSlot.__init__(self, slot_name, **kargs)
452
        self.method = method
453

454
    def _needs_own(self, scope):
455
        if (scope.parent_type.base_type
456
                and not scope.has_pyobject_attrs
457
                and not scope.has_memoryview_attrs
458
                and not scope.has_cpp_constructable_attrs
459
                and not (self.slot_name == 'tp_new' and scope.parent_type.vtabslot_cname)):
460
            entry = scope.lookup_here(self.method) if self.method else None
461
            if not (entry and entry.is_special):
462
                return False
463
        # Unless we can safely delegate to the parent, all types need a tp_new().
464
        return True
465

466
    def _parent_slot_function(self, scope):
467
        parent_type_scope = scope.parent_type.base_type.scope
468
        if scope.parent_scope is parent_type_scope.parent_scope:
469
            entry = scope.parent_scope.lookup_here(scope.parent_type.base_type.name)
470
            if entry.visibility != 'extern':
471
                return self.slot_code(parent_type_scope)
472
        return None
473

474
    def slot_code(self, scope):
475
        if not self._needs_own(scope):
476
            # if the type does not have object attributes, it can
477
            # delegate GC methods to its parent - iff the parent
478
            # functions are defined in the same module
479
            slot_code = self._parent_slot_function(scope)
480
            return slot_code or '0'
481
        return InternalMethodSlot.slot_code(self, scope)
482

483
    def spec_value(self, scope):
484
        slot_function = self.slot_code(scope)
485
        if self.slot_name == "tp_dealloc" and slot_function != scope.mangle_internal("tp_dealloc"):
486
            # Not used => inherit from base type.
487
            return "0"
488
        return slot_function
489

490
    def generate_dynamic_init_code(self, scope, code):
491
        if self.slot_code(scope) != '0':
492
            return
493
        # If we don't have our own slot function and don't know the
494
        # parent function statically, copy it dynamically.
495
        base_type = scope.parent_type.base_type
496
        if base_type.typeptr_cname:
497
            src = '%s->%s' % (base_type.typeptr_cname, self.slot_name)
498
        elif base_type.is_extension_type and base_type.typeobj_cname:
499
            src = '%s.%s' % (base_type.typeobj_cname, self.slot_name)
500
        else:
501
            return
502

503
        self.generate_set_slot_code(src, scope, code)
504

505

506
class SyntheticSlot(InternalMethodSlot):
507
    #  Type slot descriptor for a synthesized method which
508
    #  dispatches to one or more user-defined methods depending
509
    #  on its arguments. If none of the relevant methods are
510
    #  defined, the method will not be synthesized and an
511
    #  alternative default value will be placed in the type
512
    #  slot.
513

514
    def __init__(self, slot_name, user_methods, default_value, **kargs):
515
        InternalMethodSlot.__init__(self, slot_name, **kargs)
516
        self.user_methods = user_methods
517
        self.default_value = default_value
518

519
    def slot_code(self, scope):
520
        if scope.defines_any_special(self.user_methods):
521
            return InternalMethodSlot.slot_code(self, scope)
522
        else:
523
            return self.default_value
524

525
    def spec_value(self, scope):
526
        return self.slot_code(scope)
527

528

529
class BinopSlot(SyntheticSlot):
530
    def __init__(self, signature, slot_name, left_method, method_name_to_slot, **kargs):
531
        assert left_method.startswith('__')
532
        right_method = '__r' + left_method[2:]
533
        SyntheticSlot.__init__(
534
                self, slot_name, [left_method, right_method], "0", is_binop=True, **kargs)
535
        # MethodSlot causes special method registration.
536
        self.left_slot = MethodSlot(signature, "", left_method, method_name_to_slot, **kargs)
537
        self.right_slot = MethodSlot(signature, "", right_method, method_name_to_slot, **kargs)
538

539

540
class RichcmpSlot(MethodSlot):
541
    def slot_code(self, scope):
542
        entry = scope.lookup_here(self.method_name)
543
        if entry and entry.is_special and entry.func_cname:
544
            return entry.func_cname
545
        elif scope.defines_any_special(richcmp_special_methods):
546
            return scope.mangle_internal(self.slot_name)
547
        else:
548
            return "0"
549

550

551
class TypeFlagsSlot(SlotDescriptor):
552
    #  Descriptor for the type flags slot.
553

554
    def slot_code(self, scope):
555
        value = "Py_TPFLAGS_DEFAULT"
556
        if scope.directives['type_version_tag']:
557
            # it's not in 'Py_TPFLAGS_DEFAULT' in Py2
558
            value += "|Py_TPFLAGS_HAVE_VERSION_TAG"
559
        else:
560
            # it's enabled in 'Py_TPFLAGS_DEFAULT' in Py3
561
            value = "(%s&~Py_TPFLAGS_HAVE_VERSION_TAG)" % value
562
        value += "|Py_TPFLAGS_CHECKTYPES|Py_TPFLAGS_HAVE_NEWBUFFER"
563
        if not scope.parent_type.is_final_type:
564
            value += "|Py_TPFLAGS_BASETYPE"
565
        if scope.needs_gc():
566
            value += "|Py_TPFLAGS_HAVE_GC"
567
        if scope.may_have_finalize():
568
            value += "|Py_TPFLAGS_HAVE_FINALIZE"
569
        if scope.parent_type.has_sequence_flag:
570
            value += "|Py_TPFLAGS_SEQUENCE"
571
        return value
572

573
    def generate_spec(self, scope, code):
574
        # Flags are stored in the PyType_Spec, not in a PyType_Slot.
575
        return
576

577

578
class DocStringSlot(SlotDescriptor):
579
    #  Descriptor for the docstring slot.
580

581
    def slot_code(self, scope):
582
        doc = scope.doc
583
        if doc is None:
584
            return "0"
585
        if doc.is_unicode:
586
            doc = doc.as_utf8_string()
587
        return "PyDoc_STR(%s)" % doc.as_c_string_literal()
588

589

590
class SuiteSlot(SlotDescriptor):
591
    #  Descriptor for a substructure of the type object.
592
    #
593
    #  sub_slots   [SlotDescriptor]
594

595
    def __init__(self, sub_slots, slot_type, slot_name, substructures, ifdef=None, cast_cname=None):
596
        SlotDescriptor.__init__(self, slot_name, ifdef=ifdef)
597
        self.sub_slots = sub_slots
598
        self.slot_type = slot_type
599
        self.cast_cname = cast_cname
600
        substructures.append(self)
601

602
    def is_empty(self, scope):
603
        for slot in self.sub_slots:
604
            if slot.slot_code(scope) != "0":
605
                return False
606
        return True
607

608
    def substructure_cname(self, scope):
609
        return "%s%s_%s" % (Naming.pyrex_prefix, self.slot_name, scope.class_name)
610

611
    def slot_code(self, scope):
612
        if not self.is_empty(scope):
613
            cast = ""
614
            if self.cast_cname:
615
                cast = f"({self.cast_cname}*)"
616
            return f"{cast}&{self.substructure_cname(scope)}"
617
        return "0"
618

619
    def generate_substructure(self, scope, code):
620
        if not self.is_empty(scope):
621
            code.putln("")
622
            if self.ifdef:
623
                code.putln("#if %s" % self.ifdef)
624
            code.putln(
625
                "static %s %s = {" % (
626
                    self.slot_type,
627
                    self.substructure_cname(scope)))
628
            for slot in self.sub_slots:
629
                slot.generate(scope, code)
630
            code.putln("};")
631
            if self.ifdef:
632
                code.putln("#endif")
633

634
    def generate_spec(self, scope, code):
635
        for slot in self.sub_slots:
636
            slot.generate_spec(scope, code)
637

638
class MethodTableSlot(SlotDescriptor):
639
    #  Slot descriptor for the method table.
640

641
    def slot_code(self, scope):
642
        if scope.pyfunc_entries:
643
            return scope.method_table_cname
644
        else:
645
            return "0"
646

647

648
class MemberTableSlot(SlotDescriptor):
649
    #  Slot descriptor for the table of Python-accessible attributes.
650

651
    def slot_code(self, scope):
652
        # Only used in specs.
653
        return "0"
654

655
    def get_member_specs(self, scope):
656
        return [
657
            get_slot_by_name("tp_dictoffset", scope.directives).members_slot_value(scope),
658
            #get_slot_by_name("tp_weaklistoffset").spec_value(scope),
659
        ]
660

661
    def is_empty(self, scope):
662
        for member_entry in self.get_member_specs(scope):
663
            if member_entry:
664
                return False
665
        return True
666

667
    def substructure_cname(self, scope):
668
        return "%s%s_%s" % (Naming.pyrex_prefix, self.slot_name, scope.class_name)
669

670
    def generate_substructure_spec(self, scope, code):
671
        if self.is_empty(scope):
672
            return
673
        from .Code import UtilityCode
674
        code.globalstate.use_utility_code(UtilityCode.load_cached("IncludeStructmemberH", "ModuleSetupCode.c"))
675

676
        code.putln("static struct PyMemberDef %s[] = {" % self.substructure_cname(scope))
677
        for member_entry in self.get_member_specs(scope):
678
            if member_entry:
679
                code.putln(member_entry)
680
        code.putln("{NULL, 0, 0, 0, NULL}")
681
        code.putln("};")
682

683
    def spec_value(self, scope):
684
        if self.is_empty(scope):
685
            return "0"
686
        return self.substructure_cname(scope)
687

688

689
class GetSetSlot(SlotDescriptor):
690
    #  Slot descriptor for the table of attribute get & set methods.
691

692
    def slot_code(self, scope):
693
        if scope.property_entries:
694
            return scope.getset_table_cname
695
        else:
696
            return "0"
697

698

699
class BaseClassSlot(SlotDescriptor):
700
    #  Slot descriptor for the base class slot.
701

702
    def __init__(self, name):
703
        SlotDescriptor.__init__(self, name, dynamic=True)
704

705
    def generate_dynamic_init_code(self, scope, code):
706
        base_type = scope.parent_type.base_type
707
        if base_type:
708
            code.putln("%s->%s = %s;" % (
709
                scope.parent_type.typeptr_cname,
710
                self.slot_name,
711
                base_type.typeptr_cname))
712

713

714
class DictOffsetSlot(SlotDescriptor):
715
    #  Slot descriptor for a class' dict offset, for dynamic attributes.
716

717
    def slot_code(self, scope):
718
        dict_entry = scope.lookup_here("__dict__") if not scope.is_closure_class_scope else None
719
        if dict_entry and dict_entry.is_variable:
720
            from . import Builtin
721
            if dict_entry.type is not Builtin.dict_type:
722
                error(dict_entry.pos, "__dict__ slot must be of type 'dict'")
723
                return "0"
724
            type = scope.parent_type
725
            if type.typedef_flag:
726
                objstruct = type.objstruct_cname
727
            else:
728
                objstruct = "struct %s" % type.objstruct_cname
729
            return ("offsetof(%s, %s)" % (
730
                        objstruct,
731
                        dict_entry.cname))
732
        else:
733
            return "0"
734

735
    def members_slot_value(self, scope):
736
        dict_offset = self.slot_code(scope)
737
        if dict_offset == "0":
738
            return None
739
        return '{"__dictoffset__", T_PYSSIZET, %s, READONLY, NULL},' % dict_offset
740

741
## The following slots are (or could be) initialised with an
742
## extern function pointer.
743
#
744
#slots_initialised_from_extern = (
745
#    "tp_free",
746
#)
747

748
#------------------------------------------------------------------------------------------
749
#
750
#  Utility functions for accessing slot table data structures
751
#
752
#------------------------------------------------------------------------------------------
753

754

755
def get_property_accessor_signature(name):
756
    #  Return signature of accessor for an extension type
757
    #  property, else None.
758
    return property_accessor_signatures.get(name)
759

760

761
def get_base_slot_function(scope, slot):
762
    #  Returns the function implementing this slot in the baseclass.
763
    #  This is useful for enabling the compiler to optimize calls
764
    #  that recursively climb the class hierarchy.
765
    base_type = scope.parent_type.base_type
766
    if base_type and scope.parent_scope is base_type.scope.parent_scope:
767
        parent_slot = slot.slot_code(base_type.scope)
768
        if parent_slot != '0':
769
            entry = scope.parent_scope.lookup_here(scope.parent_type.base_type.name)
770
            if entry.visibility != 'extern':
771
                return parent_slot
772
    return None
773

774

775
def get_slot_function(scope, slot):
776
    #  Returns the function implementing this slot in the baseclass.
777
    #  This is useful for enabling the compiler to optimize calls
778
    #  that recursively climb the class hierarchy.
779
    slot_code = slot.slot_code(scope)
780
    if slot_code != '0':
781
        entry = scope.parent_scope.lookup_here(scope.parent_type.name)
782
        if entry.visibility != 'extern':
783
            return slot_code
784
    return None
785

786

787
def get_slot_by_name(slot_name, compiler_directives):
788
    # For now, only search the type struct, no referenced sub-structs.
789
    for slot in get_slot_table(compiler_directives).slot_table:
790
        if slot.slot_name == slot_name:
791
            return slot
792
    assert False, "Slot not found: %s" % slot_name
793

794

795
def get_slot_code_by_name(scope, slot_name):
796
    slot = get_slot_by_name(slot_name, scope.directives)
797
    return slot.slot_code(scope)
798

799
def is_binop_number_slot(name):
800
    """
801
    Tries to identify __add__/__radd__ and friends (so the METH_COEXIST flag can be applied).
802

803
    There's no great consequence if it inadvertently identifies a few other methods
804
    so just use a simple rule rather than an exact list.
805
    """
806
    slot_table = get_slot_table(None)
807
    for meth in get_slot_table(None).PyNumberMethods:
808
        if meth.is_binop and name in meth.user_methods:
809
            return True
810
    return False
811

812

813
#------------------------------------------------------------------------------------------
814
#
815
#  Signatures for generic Python functions and methods.
816
#
817
#------------------------------------------------------------------------------------------
818

819
pyfunction_signature = Signature("-*", "O")
820
pymethod_signature = Signature("T*", "O")
821

822
#------------------------------------------------------------------------------------------
823
#
824
#  Signatures for simple Python functions.
825
#
826
#------------------------------------------------------------------------------------------
827

828
pyfunction_noargs = Signature("-", "O")
829
pyfunction_onearg = Signature("-O", "O")
830

831
#------------------------------------------------------------------------------------------
832
#
833
#  Signatures for the various kinds of function that
834
#  can appear in the type object and its substructures.
835
#
836
#------------------------------------------------------------------------------------------
837

838
unaryfunc = Signature("T", "O")            # typedef PyObject * (*unaryfunc)(PyObject *);
839
binaryfunc = Signature("OO", "O")          # typedef PyObject * (*binaryfunc)(PyObject *, PyObject *);
840
ibinaryfunc = Signature("TO", "O")         # typedef PyObject * (*binaryfunc)(PyObject *, PyObject *);
841
powternaryfunc = Signature("OO?", "O")     # typedef PyObject * (*ternaryfunc)(PyObject *, PyObject *, PyObject *);
842
ipowternaryfunc = Signature("TO?", "O")    # typedef PyObject * (*ternaryfunc)(PyObject *, PyObject *, PyObject *);
843
callfunc = Signature("T*", "O")            # typedef PyObject * (*ternaryfunc)(PyObject *, PyObject *, PyObject *);
844
inquiry = Signature("T", "i")              # typedef int (*inquiry)(PyObject *);
845
lenfunc = Signature("T", "z")              # typedef Py_ssize_t (*lenfunc)(PyObject *);
846

847
                                           # typedef int (*coercion)(PyObject **, PyObject **);
848
intargfunc = Signature("Ti", "O")          # typedef PyObject *(*intargfunc)(PyObject *, int);
849
ssizeargfunc = Signature("Tz", "O")        # typedef PyObject *(*ssizeargfunc)(PyObject *, Py_ssize_t);
850
intintargfunc = Signature("Tii", "O")      # typedef PyObject *(*intintargfunc)(PyObject *, int, int);
851
ssizessizeargfunc = Signature("Tzz", "O")  # typedef PyObject *(*ssizessizeargfunc)(PyObject *, Py_ssize_t, Py_ssize_t);
852
intobjargproc = Signature("TiO", 'r')      # typedef int(*intobjargproc)(PyObject *, int, PyObject *);
853
ssizeobjargproc = Signature("TzO", 'r')    # typedef int(*ssizeobjargproc)(PyObject *, Py_ssize_t, PyObject *);
854
intintobjargproc = Signature("TiiO", 'r')  # typedef int(*intintobjargproc)(PyObject *, int, int, PyObject *);
855
ssizessizeobjargproc = Signature("TzzO", 'r')  # typedef int(*ssizessizeobjargproc)(PyObject *, Py_ssize_t, Py_ssize_t, PyObject *);
856

857
intintargproc = Signature("Tii", 'r')
858
ssizessizeargproc = Signature("Tzz", 'r')
859
objargfunc = Signature("TO", "O")
860
objobjargproc = Signature("TOO", 'r')      # typedef int (*objobjargproc)(PyObject *, PyObject *, PyObject *);
861
readbufferproc = Signature("TzP", "z")     # typedef Py_ssize_t (*readbufferproc)(PyObject *, Py_ssize_t, void **);
862
writebufferproc = Signature("TzP", "z")    # typedef Py_ssize_t (*writebufferproc)(PyObject *, Py_ssize_t, void **);
863
segcountproc = Signature("TZ", "z")        # typedef Py_ssize_t (*segcountproc)(PyObject *, Py_ssize_t *);
864
charbufferproc = Signature("TzS", "z")     # typedef Py_ssize_t (*charbufferproc)(PyObject *, Py_ssize_t, char **);
865
objargproc = Signature("TO", 'r')          # typedef int (*objobjproc)(PyObject *, PyObject *);
866
                                           # typedef int (*visitproc)(PyObject *, void *);
867
                                           # typedef int (*traverseproc)(PyObject *, visitproc, void *);
868

869
destructor = Signature("T", "v")           # typedef void (*destructor)(PyObject *);
870
# printfunc = Signature("TFi", 'r')        # typedef int (*printfunc)(PyObject *, FILE *, int);
871
                                           # typedef PyObject *(*getattrfunc)(PyObject *, char *);
872
getattrofunc = Signature("TO", "O")        # typedef PyObject *(*getattrofunc)(PyObject *, PyObject *);
873
                                           # typedef int (*setattrfunc)(PyObject *, char *, PyObject *);
874
setattrofunc = Signature("TOO", 'r')       # typedef int (*setattrofunc)(PyObject *, PyObject *, PyObject *);
875
delattrofunc = Signature("TO", 'r')
876
cmpfunc = Signature("TO", "i")             # typedef int (*cmpfunc)(PyObject *, PyObject *);
877
reprfunc = Signature("T", "O")             # typedef PyObject *(*reprfunc)(PyObject *);
878
hashfunc = Signature("T", "h")             # typedef Py_hash_t (*hashfunc)(PyObject *);
879
richcmpfunc = Signature("TOi", "O")        # typedef PyObject *(*richcmpfunc) (PyObject *, PyObject *, int);
880
getiterfunc = Signature("T", "O")          # typedef PyObject *(*getiterfunc) (PyObject *);
881
iternextfunc = Signature("T", "O")         # typedef PyObject *(*iternextfunc) (PyObject *);
882
descrgetfunc = Signature("TOO", "O")       # typedef PyObject *(*descrgetfunc) (PyObject *, PyObject *, PyObject *);
883
descrsetfunc = Signature("TOO", 'r')       # typedef int (*descrsetfunc) (PyObject *, PyObject *, PyObject *);
884
descrdelfunc = Signature("TO", 'r')
885
initproc = Signature("T*", 'r')            # typedef int (*initproc)(PyObject *, PyObject *, PyObject *);
886
                                           # typedef PyObject *(*newfunc)(struct _typeobject *, PyObject *, PyObject *);
887
                                           # typedef PyObject *(*allocfunc)(struct _typeobject *, int);
888

889
getbufferproc = Signature("TBi", "r")      # typedef int (*getbufferproc)(PyObject *, Py_buffer *, int);
890
releasebufferproc = Signature("TB", "v")   # typedef void (*releasebufferproc)(PyObject *, Py_buffer *);
891

892
# typedef PySendResult (*sendfunc)(PyObject* iter, PyObject* value, PyObject** result);
893
sendfunc = PyrexTypes.CPtrType(PyrexTypes.CFuncType(
894
        return_type=PyrexTypes.PySendResult_type,
895
        args=[
896
            PyrexTypes.CFuncTypeArg("iter", PyrexTypes.py_object_type),
897
            PyrexTypes.CFuncTypeArg("value", PyrexTypes.py_object_type),
898
            PyrexTypes.CFuncTypeArg("result", PyrexTypes.CPtrType(PyrexTypes.py_objptr_type)),
899
        ],
900
        exception_value="PYGEN_ERROR",
901
        exception_check=True,  # we allow returning PYGEN_ERROR without GeneratorExit / StopIteration
902
    ))
903

904

905
#------------------------------------------------------------------------------------------
906
#
907
#  Signatures for accessor methods of properties.
908
#
909
#------------------------------------------------------------------------------------------
910

911
property_accessor_signatures = {
912
    '__get__': Signature("T", "O"),
913
    '__set__': Signature("TO", 'r'),
914
    '__del__': Signature("T", 'r')
915
}
916

917
#------------------------------------------------------------------------------------------
918
#
919
#  The main slot table. This table contains descriptors for all the
920
#  top-level type slots, beginning with tp_dealloc, in the order they
921
#  appear in the type object.
922
#
923
# It depends on some compiler directives (currently c_api_binop_methods), so the
924
# slot tables for each set of compiler directives are generated lazily and put in
925
# the _slot_table_dict
926
#
927
#------------------------------------------------------------------------------------------
928

929
class SlotTable:
930
    def __init__(self, old_binops):
931
        # The following dictionary maps __xxx__ method names to slot descriptors.
932
        method_name_to_slot = {}
933
        self._get_slot_by_method_name = method_name_to_slot.get
934
        self.substructures = []   # List of all SuiteSlot instances
935

936
        bf = binaryfunc if old_binops else ibinaryfunc
937
        ptf = powternaryfunc if old_binops else ipowternaryfunc
938

939
        #  Descriptor tables for the slots of the various type object
940
        #  substructures, in the order they appear in the structure.
941
        self.PyNumberMethods = (
942
            BinopSlot(bf, "nb_add", "__add__", method_name_to_slot),
943
            BinopSlot(bf, "nb_subtract", "__sub__", method_name_to_slot),
944
            BinopSlot(bf, "nb_multiply", "__mul__", method_name_to_slot),
945
            BinopSlot(bf, "nb_remainder", "__mod__", method_name_to_slot),
946
            BinopSlot(bf, "nb_divmod", "__divmod__", method_name_to_slot),
947
            BinopSlot(ptf, "nb_power", "__pow__", method_name_to_slot),
948
            MethodSlot(unaryfunc, "nb_negative", "__neg__", method_name_to_slot),
949
            MethodSlot(unaryfunc, "nb_positive", "__pos__", method_name_to_slot),
950
            MethodSlot(unaryfunc, "nb_absolute", "__abs__", method_name_to_slot),
951
            MethodSlot(inquiry, "nb_bool", "__bool__", method_name_to_slot,
952
                       fallback="__nonzero__"),
953
            MethodSlot(unaryfunc, "nb_invert", "__invert__", method_name_to_slot),
954
            BinopSlot(bf, "nb_lshift", "__lshift__", method_name_to_slot),
955
            BinopSlot(bf, "nb_rshift", "__rshift__", method_name_to_slot),
956
            BinopSlot(bf, "nb_and", "__and__", method_name_to_slot),
957
            BinopSlot(bf, "nb_xor", "__xor__", method_name_to_slot),
958
            BinopSlot(bf, "nb_or", "__or__", method_name_to_slot),
959
            MethodSlot(unaryfunc, "nb_int", "__int__", method_name_to_slot, fallback="__long__"),
960
            EmptySlot("nb_long (reserved)"),
961
            MethodSlot(unaryfunc, "nb_float", "__float__", method_name_to_slot),
962

963
            # Added in release 2.0
964
            MethodSlot(ibinaryfunc, "nb_inplace_add", "__iadd__", method_name_to_slot),
965
            MethodSlot(ibinaryfunc, "nb_inplace_subtract", "__isub__", method_name_to_slot),
966
            MethodSlot(ibinaryfunc, "nb_inplace_multiply", "__imul__", method_name_to_slot),
967
            MethodSlot(ibinaryfunc, "nb_inplace_remainder", "__imod__", method_name_to_slot),
968
            MethodSlot(ptf, "nb_inplace_power", "__ipow__", method_name_to_slot),
969
            MethodSlot(ibinaryfunc, "nb_inplace_lshift", "__ilshift__", method_name_to_slot),
970
            MethodSlot(ibinaryfunc, "nb_inplace_rshift", "__irshift__", method_name_to_slot),
971
            MethodSlot(ibinaryfunc, "nb_inplace_and", "__iand__", method_name_to_slot),
972
            MethodSlot(ibinaryfunc, "nb_inplace_xor", "__ixor__", method_name_to_slot),
973
            MethodSlot(ibinaryfunc, "nb_inplace_or", "__ior__", method_name_to_slot),
974

975
            # Added in release 2.2
976
            # The following require the Py_TPFLAGS_HAVE_CLASS flag
977
            BinopSlot(bf, "nb_floor_divide", "__floordiv__", method_name_to_slot),
978
            BinopSlot(bf, "nb_true_divide", "__truediv__", method_name_to_slot),
979
            MethodSlot(ibinaryfunc, "nb_inplace_floor_divide", "__ifloordiv__", method_name_to_slot),
980
            MethodSlot(ibinaryfunc, "nb_inplace_true_divide", "__itruediv__", method_name_to_slot),
981

982
            # Added in release 2.5
983
            MethodSlot(unaryfunc, "nb_index", "__index__", method_name_to_slot),
984

985
            # Added in release 3.5
986
            BinopSlot(bf, "nb_matrix_multiply", "__matmul__", method_name_to_slot,
987
                      ifdef="PY_VERSION_HEX >= 0x03050000"),
988
            MethodSlot(ibinaryfunc, "nb_inplace_matrix_multiply", "__imatmul__", method_name_to_slot,
989
                       ifdef="PY_VERSION_HEX >= 0x03050000"),
990
        )
991

992
        self.PySequenceMethods = (
993
            MethodSlot(lenfunc, "sq_length", "__len__", method_name_to_slot),
994
            EmptySlot("sq_concat"),  # nb_add used instead
995
            EmptySlot("sq_repeat"),  # nb_multiply used instead
996
            SyntheticSlot("sq_item", ["__getitem__"], "0"),    #EmptySlot("sq_item"),   # mp_subscript used instead
997
            MethodSlot(ssizessizeargfunc, "sq_slice", "__getslice__", method_name_to_slot),
998
            EmptySlot("sq_ass_item"),  # mp_ass_subscript used instead
999
            SyntheticSlot("sq_ass_slice", ["__setslice__", "__delslice__"], "0"),
1000
            MethodSlot(cmpfunc, "sq_contains", "__contains__", method_name_to_slot),
1001
            EmptySlot("sq_inplace_concat"),  # nb_inplace_add used instead
1002
            EmptySlot("sq_inplace_repeat"),  # nb_inplace_multiply used instead
1003
        )
1004

1005
        self.PyMappingMethods = (
1006
            MethodSlot(lenfunc, "mp_length", "__len__", method_name_to_slot),
1007
            MethodSlot(objargfunc, "mp_subscript", "__getitem__", method_name_to_slot),
1008
            SyntheticSlot("mp_ass_subscript", ["__setitem__", "__delitem__"], "0"),
1009
        )
1010

1011
        self.PyBufferProcs = (
1012
            MethodSlot(getbufferproc, "bf_getbuffer", "__getbuffer__", method_name_to_slot),
1013
            MethodSlot(releasebufferproc, "bf_releasebuffer", "__releasebuffer__", method_name_to_slot)
1014
        )
1015

1016
        self.PyAsyncMethods = (
1017
            MethodSlot(unaryfunc, "am_await", "__await__", method_name_to_slot),
1018
            MethodSlot(unaryfunc, "am_aiter", "__aiter__", method_name_to_slot),
1019
            MethodSlot(unaryfunc, "am_anext", "__anext__", method_name_to_slot),
1020
            # We should not map arbitrary .send() methods to an async slot.
1021
            #MethodSlot(sendfunc, "am_send", "send", method_name_to_slot),
1022
            EmptySlot("am_send"),
1023
        )
1024

1025
        self.slot_table = (
1026
            ConstructorSlot("tp_dealloc", '__dealloc__'),
1027
            EmptySlot("tp_print", ifdef="PY_VERSION_HEX < 0x030800b4"),
1028
            EmptySlot("tp_vectorcall_offset", ifdef="PY_VERSION_HEX >= 0x030800b4"),
1029
            EmptySlot("tp_getattr"),
1030
            EmptySlot("tp_setattr"),
1031

1032
            SuiteSlot(self. PyAsyncMethods, "__Pyx_PyAsyncMethodsStruct", "tp_as_async",
1033
                      self.substructures, cast_cname="PyAsyncMethods"),
1034

1035
            MethodSlot(reprfunc, "tp_repr", "__repr__", method_name_to_slot),
1036

1037
            SuiteSlot(self.PyNumberMethods, "PyNumberMethods", "tp_as_number", self.substructures),
1038
            SuiteSlot(self.PySequenceMethods, "PySequenceMethods", "tp_as_sequence", self.substructures),
1039
            SuiteSlot(self.PyMappingMethods, "PyMappingMethods", "tp_as_mapping", self.substructures),
1040

1041
            MethodSlot(hashfunc, "tp_hash", "__hash__", method_name_to_slot,
1042
                       inherited=False),    # Py3 checks for __richcmp__
1043
            MethodSlot(callfunc, "tp_call", "__call__", method_name_to_slot),
1044
            MethodSlot(reprfunc, "tp_str", "__str__", method_name_to_slot),
1045

1046
            SyntheticSlot("tp_getattro", ["__getattr__","__getattribute__"], "0"),  #"PyObject_GenericGetAttr"),
1047
            SyntheticSlot("tp_setattro", ["__setattr__", "__delattr__"], "0"),  #"PyObject_GenericSetAttr"),
1048

1049
            SuiteSlot(self.PyBufferProcs, "PyBufferProcs", "tp_as_buffer", self.substructures),
1050

1051
            TypeFlagsSlot("tp_flags"),
1052
            DocStringSlot("tp_doc"),
1053

1054
            GCDependentSlot("tp_traverse"),
1055
            GCClearReferencesSlot("tp_clear"),
1056

1057
            RichcmpSlot(richcmpfunc, "tp_richcompare", "__richcmp__", method_name_to_slot,
1058
                        inherited=False),  # Py3 checks for __hash__
1059

1060
            EmptySlot("tp_weaklistoffset"),
1061

1062
            MethodSlot(getiterfunc, "tp_iter", "__iter__", method_name_to_slot),
1063
            MethodSlot(iternextfunc, "tp_iternext", "__next__", method_name_to_slot),
1064

1065
            MethodTableSlot("tp_methods"),
1066
            MemberTableSlot("tp_members"),
1067
            GetSetSlot("tp_getset"),
1068

1069
            BaseClassSlot("tp_base"),  #EmptySlot("tp_base"),
1070
            EmptySlot("tp_dict"),
1071

1072
            SyntheticSlot("tp_descr_get", ["__get__"], "0"),
1073
            SyntheticSlot("tp_descr_set", ["__set__", "__delete__"], "0"),
1074

1075
            DictOffsetSlot("tp_dictoffset", ifdef="!CYTHON_USE_TYPE_SPECS"),  # otherwise set via "__dictoffset__" member
1076

1077
            MethodSlot(initproc, "tp_init", "__init__", method_name_to_slot),
1078
            EmptySlot("tp_alloc"),  #FixedSlot("tp_alloc", "PyType_GenericAlloc"),
1079
            ConstructorSlot("tp_new", "__cinit__"),
1080
            EmptySlot("tp_free"),
1081

1082
            EmptySlot("tp_is_gc"),
1083
            EmptySlot("tp_bases"),
1084
            EmptySlot("tp_mro"),
1085
            EmptySlot("tp_cache"),
1086
            EmptySlot("tp_subclasses"),
1087
            EmptySlot("tp_weaklist"),
1088
            EmptySlot("tp_del"),
1089
            EmptySlot("tp_version_tag"),
1090
            SyntheticSlot("tp_finalize", ["__del__"], "0",
1091
                          used_ifdef="CYTHON_USE_TP_FINALIZE"),
1092
            EmptySlot("tp_vectorcall", ifdef="PY_VERSION_HEX >= 0x030800b1 && (!CYTHON_COMPILING_IN_PYPY || PYPY_VERSION_NUM >= 0x07030800)"),
1093
            EmptySlot("tp_print", ifdef="__PYX_NEED_TP_PRINT_SLOT == 1"),
1094
            EmptySlot("tp_watched", ifdef="PY_VERSION_HEX >= 0x030C0000"),
1095
            EmptySlot("tp_versions_used", ifdef="PY_VERSION_HEX >= 0x030d00A4"),
1096
            # PyPy specific extension - only here to avoid C compiler warnings.
1097
            EmptySlot("tp_pypy_flags", ifdef="CYTHON_COMPILING_IN_PYPY && PY_VERSION_HEX >= 0x03090000 && PY_VERSION_HEX < 0x030a0000"),
1098
        )
1099

1100
        #------------------------------------------------------------------------------------------
1101
        #
1102
        #  Descriptors for special methods which don't appear directly
1103
        #  in the type object or its substructures. These methods are
1104
        #  called from slot functions synthesized by Cython.
1105
        #
1106
        #------------------------------------------------------------------------------------------
1107

1108
        MethodSlot(initproc, "", "__cinit__", method_name_to_slot)
1109
        MethodSlot(destructor, "", "__dealloc__", method_name_to_slot)
1110
        MethodSlot(destructor, "", "__del__", method_name_to_slot)
1111
        MethodSlot(objobjargproc, "", "__setitem__", method_name_to_slot)
1112
        MethodSlot(objargproc, "", "__delitem__", method_name_to_slot)
1113
        MethodSlot(ssizessizeobjargproc, "", "__setslice__", method_name_to_slot)
1114
        MethodSlot(ssizessizeargproc, "", "__delslice__", method_name_to_slot)
1115
        MethodSlot(getattrofunc, "", "__getattr__", method_name_to_slot)
1116
        MethodSlot(getattrofunc, "", "__getattribute__", method_name_to_slot)
1117
        MethodSlot(setattrofunc, "", "__setattr__", method_name_to_slot)
1118
        MethodSlot(delattrofunc, "", "__delattr__", method_name_to_slot)
1119
        MethodSlot(descrgetfunc, "", "__get__", method_name_to_slot)
1120
        MethodSlot(descrsetfunc, "", "__set__", method_name_to_slot)
1121
        MethodSlot(descrdelfunc, "", "__delete__", method_name_to_slot)
1122

1123
        #-------------------------------------------------------------------------
1124
        #
1125
        # Legacy "fallback" Py2 slots. Don't appear in the generated slot table,
1126
        # but match the "fallback" argument of a slot that does
1127
        #
1128
        #-------------------------------------------------------------------------
1129
        MethodSlot(inquiry, "", "__nonzero__", method_name_to_slot)
1130
        MethodSlot(unaryfunc, "", "__long__", method_name_to_slot)
1131

1132
    def get_special_method_signature(self, name):
1133
        #  Given a method name, if it is a special method,
1134
        #  return its signature, else return None.
1135
        slot = self._get_slot_by_method_name(name)
1136
        if slot:
1137
            return slot.signature
1138
        elif name in richcmp_special_methods:
1139
            return ibinaryfunc
1140
        else:
1141
            return None
1142

1143
    def get_slot_by_method_name(self, method_name):
1144
        # For now, only search the type struct, no referenced sub-structs.
1145
        return self._get_slot_by_method_name(method_name)
1146

1147
    def __iter__(self):
1148
        # make it easier to iterate over all the slots
1149
        return iter(self.slot_table)
1150

1151

1152
_slot_table_dict = {}
1153

1154
def get_slot_table(compiler_directives):
1155
    if not compiler_directives:
1156
        # fetch default directives here since the builtin type classes don't have
1157
        # directives set
1158
        from .Options import get_directive_defaults
1159
        compiler_directives = get_directive_defaults()
1160

1161
    old_binops = compiler_directives['c_api_binop_methods']
1162
    key = (old_binops,)
1163
    if key not in _slot_table_dict:
1164
        _slot_table_dict[key] = SlotTable(old_binops=old_binops)
1165
    return _slot_table_dict[key]
1166

1167

1168
# Populate "special_method_names" based on the default directives (so it can always be accessed quickly).
1169
special_method_names = set(get_slot_table(compiler_directives=None))
1170

1171

1172
# Method flags for python-exposed methods.
1173

1174
method_noargs   = "METH_NOARGS"
1175
method_onearg   = "METH_O"
1176
method_varargs  = "METH_VARARGS"
1177
method_fastcall = "__Pyx_METH_FASTCALL"  # Actually VARARGS on versions < 3.7
1178
method_keywords = "METH_KEYWORDS"
1179
method_coexist  = "METH_COEXIST"
1180

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.